From 8e9a19030f4778bf1982b4ae4675d387d40a9937 Mon Sep 17 00:00:00 2001 From: onsystem Date: Sat, 22 Jul 2023 13:18:28 +0200 Subject: [PATCH 01/27] mysql-support start with docker configuration to up container and load data --- docker/docker-compose.yml | 11 ++ docker/mysql/create_tables.sql | 44 ++++++ docker/mysql/fill_tables.sql | 275 +++++++++++++++++++++++++++++++++ 3 files changed, 330 insertions(+) create mode 100644 docker/mysql/create_tables.sql create mode 100644 docker/mysql/fill_tables.sql diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 04c21b89..d24de91c 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -27,3 +27,14 @@ services: environment: MSSQL_SA_PASSWORD: "SqlServer-10" ACCEPT_EULA: "Y" + mysql: + image: mysql:latest + container_name: mysql + environment: + MYSQL_ROOT_PASSWORD: root + ports: + - '3307:3306' + volumes: + - ./mysql-data:/var/lib/mysql + - ./mysql/create_tables.sql:/docker-entrypoint-initdb.d/create_tables.sql + - ./mysql/fill_tables.sql:/docker-entrypoint-initdb.d/fill_tables.sql \ No newline at end of file diff --git a/docker/mysql/create_tables.sql b/docker/mysql/create_tables.sql new file mode 100644 index 00000000..8963767c --- /dev/null +++ b/docker/mysql/create_tables.sql @@ -0,0 +1,44 @@ +CREATE DATABASE public; + +CREATE TABLE public.league ( + id INT AUTO_INCREMENT PRIMARY KEY, + ext_id BIGINT NOT NULL, + slug TEXT NOT NULL, + name TEXT NOT NULL, + region TEXT NOT NULL, + image_url TEXT NOT NULL +); + +CREATE TABLE public.tournament ( + id INT AUTO_INCREMENT PRIMARY KEY, + ext_id BIGINT NOT NULL, + slug TEXT NOT NULL, + start_date DATE NOT NULL, + end_date DATE NOT NULL, + league INT, + FOREIGN KEY (league) REFERENCES league(id) + +); + +CREATE TABLE public.player ( + id INT AUTO_INCREMENT PRIMARY KEY, + ext_id BIGINT NOT NULL, + first_name TEXT NOT NULL, + last_name TEXT NOT NULL, + summoner_name TEXT NOT NULL, + image_url TEXT, + role TEXT NOT NULL +); + +CREATE TABLE public.team ( + id INT AUTO_INCREMENT PRIMARY KEY, + ext_id BIGINT NOT NULL, + slug TEXT NOT NULL, + name TEXT NOT NULL, + code TEXT NOT NULL, + image_url TEXT NOT NULL, + alt_image_url TEXT, + bg_image_url TEXT, + home_league INT, + FOREIGN KEY (home_league) REFERENCES league(id) +); diff --git a/docker/mysql/fill_tables.sql b/docker/mysql/fill_tables.sql new file mode 100644 index 00000000..84eff356 --- /dev/null +++ b/docker/mysql/fill_tables.sql @@ -0,0 +1,275 @@ +-- Values for league table +INSERT INTO public.league VALUES (1, 100695891328981122, 'european-masters', 'European Masters', 'EUROPE', 'http://static.lolesports.com/leagues/EM_Bug_Outline1.png'); +INSERT INTO public.league VALUES (2, 101097443346691685, 'turkey-academy-league', 'TAL', 'TURKEY', 'http://static.lolesports.com/leagues/1592516072459_TAL-01-FullonDark.png'); +INSERT INTO public.league VALUES (3, 101382741235120470, 'lla', 'LLA', 'LATIN AMERICA', 'http://static.lolesports.com/leagues/1592516315279_LLA-01-FullonDark.png'); +INSERT INTO public.league VALUES (4, 104366947889790212, 'pcs', 'PCS', 'HONG KONG, MACAU, TAIWAN', 'http://static.lolesports.com/leagues/1592515942679_PCS-01-FullonDark.png'); +INSERT INTO public.league VALUES (5, 105266074488398661, 'superliga', 'SuperLiga', 'EUROPE', 'http://static.lolesports.com/leagues/SL21-V-white.png'); +INSERT INTO public.league VALUES (6, 105266088231437431, 'ultraliga', 'Ultraliga', 'EUROPE', 'http://static.lolesports.com/leagues/1639390623717_ULTRALIGA_logo_sq_cyan.png'); +INSERT INTO public.league VALUES (7, 105266091639104326, 'primeleague', 'Prime League', 'EUROPE', 'http://static.lolesports.com/leagues/PrimeLeagueResized.png'); +INSERT INTO public.league VALUES (8, 105266094998946936, 'pg_nationals', 'PG Nationals', 'EUROPE', 'http://static.lolesports.com/leagues/PG_Nationals_Logo_White.png'); +INSERT INTO public.league VALUES (9, 105266098308571975, 'nlc', 'NLC', 'EUROPE', 'http://static.lolesports.com/leagues/1641490922073_nlc_logo.png'); +INSERT INTO public.league VALUES (10, 105266101075764040, 'liga_portuguesa', 'Liga Portuguesa', 'EUROPE', 'http://static.lolesports.com/leagues/1649884876085_LPLOL_2021_ISO_G-c389e9ae85c243e4f76a8028bbd9ca1609c2d12bc47c3709a9250d1b3ca43f58.png'); +INSERT INTO public.league VALUES (11, 105266103462388553, 'lfl', 'La Ligue Française', 'EUROPE', 'http://static.lolesports.com/leagues/LFL_Logo_2020_black1.png'); +INSERT INTO public.league VALUES (12, 105266106309666619, 'hitpoint_masters', 'Hitpoint Masters', 'EUROPE', 'http://static.lolesports.com/leagues/1641465237186_HM_white.png'); +INSERT INTO public.league VALUES (13, 105266108767593290, 'greek_legends', 'Greek Legends League', 'EUROPE', 'http://static.lolesports.com/leagues/GLL_LOGO_WHITE.png'); +INSERT INTO public.league VALUES (14, 105266111679554379, 'esports_balkan_league', 'Esports Balkan League', 'EUROPE', 'http://static.lolesports.com/leagues/1625735031226_ebl_crest-whitePNG.png'); +INSERT INTO public.league VALUES (15, 105549980953490846, 'cblol_academy', 'CBLOL Academy', 'BRAZIL', 'http://static.lolesports.com/leagues/cblol-acad-white.png'); +INSERT INTO public.league VALUES (16, 105709090213554609, 'lco', 'LCO', 'OCEANIA', 'http://static.lolesports.com/leagues/lco-color-white.png'); +INSERT INTO public.league VALUES (17, 106827757669296909, 'ljl_academy', 'LJL Academy', 'JAPAN', 'http://static.lolesports.com/leagues/1630062215891_ljl-al_logo_gradient.png'); +INSERT INTO public.league VALUES (18, 107213827295848783, 'vcs', 'VCS', 'VIETNAM', 'http://static.lolesports.com/leagues/1635953171501_LOL_VCS_Full_White.png'); +INSERT INTO public.league VALUES (19, 107407335299756365, 'elite_series', 'Elite Series', 'EUROPE', 'http://static.lolesports.com/leagues/1641287979138_EliteSeriesMarkWhite.png'); +INSERT INTO public.league VALUES (20, 107581050201097472, 'honor_division', 'Honor Division', 'LATIN AMERICA', 'http://static.lolesports.com/leagues/1641750781829_divhonormxwhite.png'); +INSERT INTO public.league VALUES (21, 107581669166925444, 'elements_league', 'Elements League', 'LATIN AMERICA', 'http://static.lolesports.com/leagues/1642593573670_LOGO_ELEMENTS_White.png'); +INSERT INTO public.league VALUES (22, 107582133359724496, 'volcano_discover_league', 'Volcano League', 'LATIN AMERICA', 'http://static.lolesports.com/leagues/1643106609661_VOLCANO-VERTICAL-ColorLight.png'); +INSERT INTO public.league VALUES (23, 107582580502415838, 'claro_gaming_stars_league', 'Stars League', 'LATIN AMERICA', 'http://static.lolesports.com/leagues/1642595169468_CLARO-GAMING-STARS-LEAGUE-B.png'); +INSERT INTO public.league VALUES (24, 107598636564896416, 'master_flow_league', 'Master Flow League', 'LATIN AMERICA', 'http://static.lolesports.com/leagues/1643794656405_LMF-White.png'); +INSERT INTO public.league VALUES (25, 107598951349015984, 'honor_league', 'Honor League', 'LATIN AMERICA', 'http://static.lolesports.com/leagues/1643036660690_lhe-ColorLight.png'); +INSERT INTO public.league VALUES (26, 107603541524308819, 'movistar_fiber_golden_league', 'Golden League', 'LATIN AMERICA', 'http://static.lolesports.com/leagues/1642445572375_MovistarLeague.png'); +INSERT INTO public.league VALUES (27, 107898214974993351, 'college_championship', 'College Championship', 'NORTH AMERICA', 'http://static.lolesports.com/leagues/1646396098648_CollegeChampionshiplogo.png'); +INSERT INTO public.league VALUES (28, 107921249454961575, 'proving_grounds', 'Proving Grounds', 'NORTH AMERICA', 'http://static.lolesports.com/leagues/1646747578708_download8.png'); +INSERT INTO public.league VALUES (29, 108001239847565215, 'tft_esports', 'TFT Last Chance Qualifier', 'INTERNATIONAL', 'http://static.lolesports.com/leagues/1649439858579_tftesport.png'); +INSERT INTO public.league VALUES (30, 98767975604431411, 'worlds', 'Worlds', 'INTERNATIONAL', 'http://static.lolesports.com/leagues/1592594612171_WorldsDarkBG.png'); +INSERT INTO public.league VALUES (31, 98767991295297326, 'all-star', 'All-Star Event', 'INTERNATIONAL', 'http://static.lolesports.com/leagues/1592594737227_ASEDarkBG.png'); +INSERT INTO public.league VALUES (32, 98767991299243165, 'lcs', 'LCS', 'NORTH AMERICA', 'http://static.lolesports.com/leagues/LCSNew-01-FullonDark.png'); +INSERT INTO public.league VALUES (33, 98767991302996019, 'lec', 'LEC', 'EUROPE', 'http://static.lolesports.com/leagues/1592516184297_LEC-01-FullonDark.png'); +INSERT INTO public.league VALUES (34, 98767991310872058, 'lck', 'LCK', 'KOREA', 'http://static.lolesports.com/leagues/lck-color-on-black.png'); +INSERT INTO public.league VALUES (35, 98767991314006698, 'lpl', 'LPL', 'CHINA', 'http://static.lolesports.com/leagues/1592516115322_LPL-01-FullonDark.png'); +INSERT INTO public.league VALUES (36, 98767991325878492, 'msi', 'MSI', 'INTERNATIONAL', 'http://static.lolesports.com/leagues/1592594634248_MSIDarkBG.png'); +INSERT INTO public.league VALUES (37, 98767991332355509, 'cblol-brazil', 'CBLOL', 'BRAZIL', 'http://static.lolesports.com/leagues/cblol-logo-symbol-offwhite.png'); +INSERT INTO public.league VALUES (38, 98767991335774713, 'lck_challengers_league', 'LCK Challengers', 'KOREA', 'http://static.lolesports.com/leagues/lck-cl-white.png'); +INSERT INTO public.league VALUES (39, 98767991343597634, 'turkiye-sampiyonluk-ligi', 'TCL', 'TURKEY', 'https://lolstatic-a.akamaihd.net/esports-assets/production/league/turkiye-sampiyonluk-ligi-8r9ofb9.png'); +INSERT INTO public.league VALUES (40, 98767991349978712, 'ljl-japan', 'LJL', 'JAPAN', 'http://static.lolesports.com/leagues/1592516354053_LJL-01-FullonDark.png'); +INSERT INTO public.league VALUES (41, 98767991355908944, 'lcl', 'LCL', 'COMMONWEALTH OF INDEPENDENT STATES', 'http://static.lolesports.com/leagues/1593016885758_LCL-01-FullonDark.png'); +INSERT INTO public.league VALUES (42, 99332500638116286, 'lcs-academy', 'LCS Academy', 'NORTH AMERICA', 'http://static.lolesports.com/leagues/lcs-academy-purple.png'); + + +-- Values for player table +INSERT INTO public.player VALUES (1, 98767975906852059, 'Jaehyeok', 'Park', 'Ruler', 'http://static.lolesports.com/players/1642153903692_GEN_Ruler_F.png', 'bottom'); +INSERT INTO public.player VALUES (2, 102186485482484390, 'Hyeonjun', 'Choi', 'Doran', 'http://static.lolesports.com/players/1642153880932_GEN_Doran_F.png', 'top'); +INSERT INTO public.player VALUES (3, 98767975916458257, 'Wangho ', 'Han', 'Peanut', 'http://static.lolesports.com/players/1642153896918_GEN_peanut_A.png', 'jungle'); +INSERT INTO public.player VALUES (4, 99871276342168416, 'Jihun', 'Jung', 'Chovy', 'http://static.lolesports.com/players/1642153873969_GEN_Chovy_F.png', 'mid'); +INSERT INTO public.player VALUES (5, 99871276332909841, 'Siu', 'Son', 'Lehends', 'http://static.lolesports.com/players/1642153887731_GEN_Lehends_F.png', 'support'); +INSERT INTO public.player VALUES (6, 104266797862156067, 'Youngjae', 'Ko', 'YoungJae', 'http://static.lolesports.com/players/1642153913037_GEN_YoungJae_F.png', 'jungle'); +INSERT INTO public.player VALUES (7, 103495716560217968, 'Hyoseong', 'Oh', 'Vsta', 'http://static.lolesports.com/players/1642154102606_HLE_Vsta_F.png', 'support'); +INSERT INTO public.player VALUES (8, 104266795407626462, 'Dongju', 'Lee', 'DuDu', 'http://static.lolesports.com/players/1642154060441_HLE_DuDu_F.png', 'top'); +INSERT INTO public.player VALUES (9, 106267386230851795, 'Junghyeun', 'Kim', 'Willer', 'http://static.lolesports.com/players/1642154110676_HLE_Willer_F.png', 'jungle'); +INSERT INTO public.player VALUES (10, 100725844995692264, 'Janggyeom', 'Kim', 'OnFleek', 'http://static.lolesports.com/players/1642154084709_HLE_Onfleek_F.png', 'jungle'); +INSERT INTO public.player VALUES (11, 105320683858945274, 'Hongjo', 'Kim', 'Karis', 'http://static.lolesports.com/players/1642154066010_HLE_Karis_F.png', 'mid'); +INSERT INTO public.player VALUES (12, 104287359934240404, 'Jaehoon', 'Lee', 'SamD', 'http://static.lolesports.com/players/1642154094651_HLE_SamD_F.png', 'bottom'); +INSERT INTO public.player VALUES (13, 103461966870841210, 'Wyllian', 'Adriano', 'asta', 'http://static.lolesports.com/players/1643226025146_Astacopy.png', 'jungle'); +INSERT INTO public.player VALUES (14, 107559111166843860, 'Felipe', 'Boal', 'Boal', 'http://static.lolesports.com/players/1644095483228_BOALcopiar.png', 'top'); +INSERT INTO public.player VALUES (15, 107559255871511679, 'Giovani', 'Baldan', 'Mito', 'http://static.lolesports.com/players/1643226193262_Mitocopy.png', 'top'); +INSERT INTO public.player VALUES (16, 103478281329357326, 'Arthur', 'Machado', 'Tutsz', 'http://static.lolesports.com/players/1643226293749_Tutszcopy.png', 'mid'); +INSERT INTO public.player VALUES (17, 103743599797538329, 'Luiz Felipe', 'Lobo', 'Flare', 'http://static.lolesports.com/players/1643226082718_Flarecopy.png', 'bottom'); +INSERT INTO public.player VALUES (18, 99566408210057665, 'Natan', 'Braz', 'fNb', 'http://static.lolesports.com/players/1643226467130_Fnbcopiar.png', 'top'); +INSERT INTO public.player VALUES (19, 99566407771166805, 'Filipe', 'Brombilla', 'Ranger', 'http://static.lolesports.com/players/1643226495379_Rangercopiar.png', 'jungle'); +INSERT INTO public.player VALUES (20, 107559327426244686, 'Vinícius', 'Corrêa', 'StineR', 'http://static.lolesports.com/players/1643226666563_Silhueta.png', 'jungle'); +INSERT INTO public.player VALUES (21, 99566407784212776, 'Bruno', 'Farias', 'Envy', 'http://static.lolesports.com/players/1643226430923_Envycopiar.png', 'mid'); +INSERT INTO public.player VALUES (22, 107559338252333149, 'Gabriel', 'Furuuti', 'Fuuu', 'http://static.lolesports.com/players/1643226717192_Silhueta.png', 'mid'); +INSERT INTO public.player VALUES (23, 105397181199735591, 'Lucas', 'Fensterseifer', 'Netuno', 'http://static.lolesports.com/players/1644095521735_Netunocopiar.png', 'bottom'); +INSERT INTO public.player VALUES (24, 98767975947296513, 'Ygor', 'Freitas', 'RedBert', 'http://static.lolesports.com/players/1643226527904_Redbertcopiar.png', 'support'); +INSERT INTO public.player VALUES (25, 100754278890207800, 'Geonyeong', 'Mun', 'Steal', 'http://static.lolesports.com/players/1644905307225_dfm_steal.png', 'jungle'); +INSERT INTO public.player VALUES (26, 99566404536983507, 'Chanju', 'Lee', 'Yaharong', 'http://static.lolesports.com/players/1644905328869_dfm_yaharong.png', 'mid'); +INSERT INTO public.player VALUES (27, 104016425624023728, 'Jiyoong', 'Lee', 'Harp', 'http://static.lolesports.com/players/1644905257358_dfm_harp.png', 'support'); +INSERT INTO public.player VALUES (28, 98767991750309549, 'Danil', 'Reshetnikov', 'Diamondprox', 'http://static.lolesports.com/players/Diamondproxcopy.png', 'jungle'); +INSERT INTO public.player VALUES (29, 105700748891875072, 'Nikita ', 'Gudkov', 'Griffon ', 'http://static.lolesports.com/players/1642071116433_placeholder.png', 'mid'); +INSERT INTO public.player VALUES (30, 105700946934214905, 'YEVHEN', 'ZAVALNYI', 'Mytant', 'http://static.lolesports.com/players/1642071138150_placeholder.png', 'bottom'); +INSERT INTO public.player VALUES (31, 98767991755955790, 'Eduard', 'Abgaryan', 'Edward', 'https://lolstatic-a.akamaihd.net/esports-assets/production/player/gosu-pepper-88anxcql.png', 'support'); +INSERT INTO public.player VALUES (32, 106301600611225723, 'Mark', 'Leksin', 'Dreampull', 'http://static.lolesports.com/players/placeholder.jpg', 'top'); +INSERT INTO public.player VALUES (33, 107721938219680332, 'Azamat', 'Atkanov', 'TESLA', 'http://static.lolesports.com/players/1643706327509_placeholder.png', 'support'); +INSERT INTO public.player VALUES (34, 100725844988653773, 'Su', 'Heo', 'ShowMaker', 'http://static.lolesports.com/players/1642153659258_DK_ShowMaker_F.png', 'mid'); +INSERT INTO public.player VALUES (35, 102483272156027229, 'Daegil', 'Seo', 'deokdam', 'http://static.lolesports.com/players/1642153629340_DK_deokdam_F.png', 'bottom'); +INSERT INTO public.player VALUES (36, 101388913291808185, 'Hyeonggyu', 'Kim', 'Kellin', 'http://static.lolesports.com/players/1642153649009_DK_Kellin_F.png', 'support'); +INSERT INTO public.player VALUES (37, 105705431649727017, 'Taeyoon', 'Noh', 'Burdol', 'http://static.lolesports.com/players/1642153598672_DK_Burdol_F.png', 'top'); +INSERT INTO public.player VALUES (38, 103729432252832975, 'Yongho', 'Yoon', 'Hoya', 'http://static.lolesports.com/players/1642153639500_DK_Hoya_F.png', 'top'); +INSERT INTO public.player VALUES (39, 105320703008048707, 'Dongbum', 'Kim', 'Croco', 'http://static.lolesports.com/players/1642154712531_LSB_Croco_R.png', 'jungle'); +INSERT INTO public.player VALUES (40, 105501829364113001, 'Hobin', 'Jeon', 'Howling', 'http://static.lolesports.com/players/1642154731703_LSB_Howling_F.png', 'top'); +INSERT INTO public.player VALUES (41, 104284310661848687, 'Juhyeon', 'Lee', 'Clozer', 'http://static.lolesports.com/players/1642154706000_LSB_Clozer_R.png', 'mid'); +INSERT INTO public.player VALUES (42, 100725844996918206, 'Jaeyeon', 'Kim', 'Dove', 'http://static.lolesports.com/players/1642154719503_LSB_Dove_R.png', 'top'); +INSERT INTO public.player VALUES (43, 105530583598805234, 'Myeongjun', 'Lee', 'Envyy', 'http://static.lolesports.com/players/1642154726047_LSB_Envyy_F.png', 'bottom'); +INSERT INTO public.player VALUES (44, 105530584812980593, 'Jinhong', 'Kim', 'Kael', 'http://static.lolesports.com/players/1642154745002_LSB_Kael_F.png', 'support'); +INSERT INTO public.player VALUES (45, 105501834624360050, 'Sanghoon', 'Yoon', 'Ice', 'http://static.lolesports.com/players/1642154738262_LSB_Ice_F.png', 'bottom'); +INSERT INTO public.player VALUES (46, 99322214647978964, 'Daniele', 'di Mauro', 'Jiizuke', 'http://static.lolesports.com/players/eg-jiizuke-2021.png', 'mid'); +INSERT INTO public.player VALUES (47, 100787602257283436, 'Minh Loc', 'Pham', 'Zeros', 'https://lolstatic-a.akamaihd.net/esports-assets/production/player/zeros-4keddu17.png', 'top'); +INSERT INTO public.player VALUES (48, 104327502738107767, 'Nicolás', 'Rivero', 'Kiefer', 'http://static.lolesports.com/players/1643047365591_Kiefer-2.png', 'mid'); +INSERT INTO public.player VALUES (49, 102179902322952953, 'Manuel', 'Scala', 'Pancake', 'http://static.lolesports.com/players/1643047550782_Pancake-5.png', 'bottom'); +INSERT INTO public.player VALUES (50, 105516185566739968, 'Cristóbal', 'Arróspide', 'Zothve', 'http://static.lolesports.com/players/1643047287141_Zothve-9.png', 'top'); +INSERT INTO public.player VALUES (51, 99871352196477603, 'Gwanghyeop', 'Kim', 'Hoglet', 'http://static.lolesports.com/players/1643047312405_Hoglet-8.png', 'jungle'); +INSERT INTO public.player VALUES (52, 99871352193690418, 'Changhun', 'Han', 'Luci', 'http://static.lolesports.com/players/1643047438703_Luci-5.png', 'support'); +INSERT INTO public.player VALUES (53, 107635899693202699, 'Thomas', 'Garnsworthy', 'Tronthepom', 'https://static.lolesports.com/players/download.png', 'top'); +INSERT INTO public.player VALUES (54, 107635905118503535, 'James', 'Craig', 'Voice', 'https://static.lolesports.com/players/download.png', 'bottom'); +INSERT INTO public.player VALUES (55, 107635907168238086, 'Rocco', 'Potter', 'rocco521', 'https://static.lolesports.com/players/download.png', 'support'); +INSERT INTO public.player VALUES (56, 107635918452357647, 'Reuben', 'Best', 'Reufury', 'https://static.lolesports.com/players/download.png', 'mid'); +INSERT INTO public.player VALUES (57, 107647480732814180, 'Bryce', 'Zhou', 'Meifan', 'https://static.lolesports.com/players/download.png', 'jungle'); +INSERT INTO public.player VALUES (58, 107657801460158111, 'Benny', 'Nguyen', 'District 1', 'https://static.lolesports.com/players/download.png', 'jungle'); +INSERT INTO public.player VALUES (59, 105709372540742118, 'Blake', 'Schlage', 'Azus', 'http://static.lolesports.com/players/silhouette.png', 'top'); +INSERT INTO public.player VALUES (60, 106350759376304634, 'Shao', 'Zhong', 'Akano', 'https://static.lolesports.com/players/download.png', 'jungle'); +INSERT INTO public.player VALUES (61, 107634941727734818, 'Jeremy', 'Lim', 'foreigner', 'https://static.lolesports.com/players/download.png', 'jungle'); +INSERT INTO public.player VALUES (62, 105709381466108761, 'Reuben', 'Salb', 'Piglet', 'http://static.lolesports.com/players/silhouette.png', 'bottom'); +INSERT INTO public.player VALUES (63, 105747861836427633, 'Yi', 'Chen', 'Thomas Shen', 'https://static.lolesports.com/players/download.png', 'bottom'); +INSERT INTO public.player VALUES (64, 107657786356796634, 'Robert', 'Wells', 'Tyran', 'https://static.lolesports.com/players/download.png', 'top'); +INSERT INTO public.player VALUES (65, 107657790493529410, 'Da Woon', 'Jeung', 'DaJeung', 'https://static.lolesports.com/players/download.png', 'mid'); +INSERT INTO public.player VALUES (66, 107657793079479518, 'Rhett', 'Wiggins', 'Vxpir', 'https://static.lolesports.com/players/download.png', 'support'); +INSERT INTO public.player VALUES (67, 107698225510856278, 'Benson', 'Tsai', 'Entrust', 'https://static.lolesports.com/players/download.png', 'support'); +INSERT INTO public.player VALUES (68, 103525219435043049, 'Lachlan', 'Keene-O''Keefe', 'N0body', 'https://lolstatic-a.akamaihd.net/esports-assets/production/player/n0body-einjqvyk.png', 'top'); +INSERT INTO public.player VALUES (69, 101389749294612370, 'Janik', 'Bartels', 'Jenax', 'http://static.lolesports.com/players/1642003381408_jenax.png', 'top'); +INSERT INTO public.player VALUES (70, 101383793865143549, 'Erik', 'Wessén', 'Treatz', 'http://static.lolesports.com/players/1642003495533_treatz.png', 'support'); +INSERT INTO public.player VALUES (71, 101389737455173027, 'Daniyal ', 'Gamani', 'Sertuss', 'http://static.lolesports.com/players/1642003453914_sertuss.png', 'mid'); +INSERT INTO public.player VALUES (72, 99322214588927915, 'Erberk ', 'Demir', 'Gilius', 'http://static.lolesports.com/players/1642003341615_gilius.png', 'jungle'); +INSERT INTO public.player VALUES (73, 99322214668103078, 'Matti', 'Sormunen', 'WhiteKnight', 'http://static.lolesports.com/players/1642003243059_white-knight.png', 'top'); +INSERT INTO public.player VALUES (74, 100312190807221865, 'Nikolay ', 'Akatov', 'Zanzarah', 'http://static.lolesports.com/players/1642003282324_zanzarah.png', 'jungle'); +INSERT INTO public.player VALUES (75, 99322214243134013, 'Hampus ', 'Abrahamsson', 'promisq', 'http://static.lolesports.com/players/1642003205916_promisq.png', 'support'); +INSERT INTO public.player VALUES (76, 99322214620375780, 'Kasper', 'Kobberup', 'Kobbe', 'http://static.lolesports.com/players/1642003168563_kobbe.png', 'bottom'); +INSERT INTO public.player VALUES (77, 99322214238585389, 'Patrik', 'Jiru', 'Patrik', 'http://static.lolesports.com/players/1642004060212_patrik.png', 'bottom'); +INSERT INTO public.player VALUES (78, 105519722481834694, 'Mark', 'van Woensel', 'Markoon', 'http://static.lolesports.com/players/1642003998089_markoon.png', 'jungle'); +INSERT INTO public.player VALUES (79, 105519724699493915, 'Hendrik', 'Reijenga', 'Advienne', 'http://static.lolesports.com/players/1642003935782_advienne.png', 'support'); +INSERT INTO public.player VALUES (80, 99322214616775017, 'Erlend', 'Holm', 'Nukeduck', 'http://static.lolesports.com/players/1642004031937_nukeduck.png', 'mid'); +INSERT INTO public.player VALUES (81, 101389713973624205, 'Finn', 'Wiestål', 'Finn', 'http://static.lolesports.com/players/1642003970167_finn.png', 'top'); +INSERT INTO public.player VALUES (82, 99322214629661297, 'Mihael', 'Mehle', 'Mikyx', 'http://static.lolesports.com/players/G2_MIKYX2021_summer.png', 'support'); +INSERT INTO public.player VALUES (83, 100482247959137902, 'Emil', 'Larsson', 'Larssen', 'http://static.lolesports.com/players/1642003206398_larssen.png', 'mid'); +INSERT INTO public.player VALUES (84, 99322214598412197, 'Andrei', 'Pascu', 'Odoamne', 'http://static.lolesports.com/players/1642003264169_odoamne.png', 'top'); +INSERT INTO public.player VALUES (85, 102181528883745160, 'Adrian', 'Trybus', 'Trymbi', 'http://static.lolesports.com/players/1642003301461_trymbi.png', 'support'); +INSERT INTO public.player VALUES (86, 99566406053904433, 'Geun-seong', 'Kim', 'Malrang', 'http://static.lolesports.com/players/1642003233110_malrang.png', 'jungle'); +INSERT INTO public.player VALUES (87, 103536921420956640, 'Markos', 'Stamkopoulos', 'Comp', 'http://static.lolesports.com/players/1642003175488_comp.png', 'bottom'); +INSERT INTO public.player VALUES (88, 101388912808637770, 'Hanxi', 'Xia', 'Chelizi', 'http://static.lolesports.com/players/1593128001829_silhouette.png', 'top'); +INSERT INTO public.player VALUES (89, 105516474039500339, 'Fei-Yang', 'Luo', 'Captain', 'http://static.lolesports.com/players/silhouette.png', 'mid'); +INSERT INTO public.player VALUES (90, 106368709696011395, 'Seung Min', 'Han', 'Patch', 'http://static.lolesports.com/players/silhouette.png', 'support'); +INSERT INTO public.player VALUES (91, 107597376599119596, 'HAOTIAN', 'BI', 'yaoyao', 'http://static.lolesports.com/players/1641805668544_placeholder.png', 'support'); +INSERT INTO public.player VALUES (92, 101388912811586896, 'Zhilin', 'Su', 'Southwind', 'http://static.lolesports.com/players/1593129903866_ig-southwind-web.png', 'support'); +INSERT INTO public.player VALUES (93, 101388912810603854, 'Wang', 'Ding', 'Puff', 'http://static.lolesports.com/players/1593129891452_ig-puff-web.png', 'bottom'); +INSERT INTO public.player VALUES (94, 104287371427354335, 'Zhi-Peng', 'Tian', 'New', 'http://static.lolesports.com/players/1593132511529_rng-new-web.png', 'top'); +INSERT INTO public.player VALUES (95, 107597380474228562, 'WANG', 'XIN', 'frigid', 'http://static.lolesports.com/players/1641805726386_placeholder.png', 'jungle'); +INSERT INTO public.player VALUES (96, 104287365097341858, 'Peng', 'Guo', 'ppgod', 'http://static.lolesports.com/players/1593135580022_v5-ppgod-web.png', 'support'); +INSERT INTO public.player VALUES (97, 103478281359738222, 'Qi-Shen ', 'Ying', 'Photic', 'https://lolstatic-a.akamaihd.net/esports-assets/production/player/photic-k1ttlyxh.png', 'bottom'); +INSERT INTO public.player VALUES (98, 103478281402167891, 'Xiao-Long ', 'Li', 'XLB', 'http://static.lolesports.com/players/1593132528126_rng-xlb-web.png', 'jungle'); +INSERT INTO public.player VALUES (99, 102186438403674539, 'Jaewon', 'Lee', 'Rich', 'http://static.lolesports.com/players/ns-rich.png', 'top'); +INSERT INTO public.player VALUES (100, 99124844346233375, 'Onur', 'Ünalan', 'Zergsting', 'http://static.lolesports.com/players/1633542837856_gs-zergsting-w21.png', 'support'); + + +-- Values for team table +INSERT INTO public.team VALUES (1, 100205573495116443, 'geng', 'Gen.G', 'GEN', 'http://static.lolesports.com/teams/1631819490111_geng-2021-worlds.png', 'http://static.lolesports.com/teams/1592589327624_Gen.GGEN-03-FullonLight.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/geng-bnm75bf5.png', 34); +INSERT INTO public.team VALUES (2, 100205573496804586, 'hanwha-life-esports', 'Hanwha Life Esports', 'HLE', 'http://static.lolesports.com/teams/1631819564399_hle-2021-worlds.png', 'http://static.lolesports.com/teams/hle-2021-color-on-light2.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/hanwha-life-esports-7kh5kjdc.png', 34); +INSERT INTO public.team VALUES (3, 100205576307813373, 'flamengo-esports', 'Flamengo Esports', 'FLA', 'http://static.lolesports.com/teams/1642953977323_Monograma_Branco-Vermelho.png', 'http://static.lolesports.com/teams/1642953977326_Monograma_Branco-Vermelho.png', NULL, 37); +INSERT INTO public.team VALUES (4, 100205576309502431, 'furia', 'FURIA', 'FUR', 'http://static.lolesports.com/teams/FURIA---black.png', 'http://static.lolesports.com/teams/FURIA---black.png', 'http://static.lolesports.com/teams/FuriaUppercutFUR.png', 37); +INSERT INTO public.team VALUES (5, 100285330168091787, 'detonation-focusme', 'DetonatioN FocusMe', 'DFM', 'http://static.lolesports.com/teams/1631820630246_dfm-2021-worlds.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/detonation-focusme-ajvyc8cy.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/detonation-focusme-4pgp383l.png', 40); +INSERT INTO public.team VALUES (6, 100289931264192378, 'team-spirit', 'Team Spirit', 'TSPT', 'http://static.lolesports.com/teams/1643720491696_Whitelogo.png', 'http://static.lolesports.com/teams/1643720491697_Blacklogo.png', NULL, 41); +INSERT INTO public.team VALUES (7, 100725845018863243, 'dwg-kia', 'DWG KIA', 'DK', 'http://static.lolesports.com/teams/1631819456274_dwg-kia-2021-worlds.png', 'http://static.lolesports.com/teams/DK-FullonLight.png', 'http://static.lolesports.com/teams/DamwonGamingDWG.png', 34); +INSERT INTO public.team VALUES (8, 100725845022060229, 'liiv-sandbox', 'Liiv SANDBOX', 'LSB', 'http://static.lolesports.com/teams/liiv-sandbox-new.png', 'http://static.lolesports.com/teams/liiv-sandbox-new.png', NULL, 34); +INSERT INTO public.team VALUES (9, 101157821444002947, 'nexus-blitz-pro-a', 'Nexus Blitz Blue', 'NXB', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/nexus-blitz-pro-a-esrcx58b.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/nexus-blitz-pro-a-3w3j1cwx.png', NULL, 31); +INSERT INTO public.team VALUES (10, 101157821447017610, 'nexus-blitz-pro-b', 'Nexus Blitz Red', 'NXR', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/nexus-blitz-pro-b-j6s80wmi.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/nexus-blitz-pro-b-kjtp467.png', NULL, 31); +INSERT INTO public.team VALUES (11, 101383792559569368, 'all-knights', 'All Knights', 'AK', 'http://static.lolesports.com/teams/AK-Black-BG.png', 'http://static.lolesports.com/teams/AK-White-BG.png', NULL, 3); +INSERT INTO public.team VALUES (12, 101383792887446028, 'mammoth', 'MAMMOTH', 'MEC', 'http://static.lolesports.com/teams/1643079304055_RedMammothIcon.png', 'http://static.lolesports.com/teams/1643079304062_RedMammothIcon.png', NULL, 16); +INSERT INTO public.team VALUES (13, 101383792891050518, 'gravitas', 'Gravitas', 'GRV', 'http://static.lolesports.com/teams/gravitas-logo.png', 'http://static.lolesports.com/teams/gravitas-logo.png', NULL, 16); +INSERT INTO public.team VALUES (14, 101383793567806688, 'sk-gaming', 'SK Gaming', 'SK', 'http://static.lolesports.com/teams/1643979272144_SK_Monochrome.png', 'http://static.lolesports.com/teams/1643979272151_SK_Monochrome.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/sk-gaming-2cd63tzz.png', 33); +INSERT INTO public.team VALUES (15, 101383793569248484, 'astralis', 'Astralis', 'AST', 'http://static.lolesports.com/teams/AST-FullonDark.png', 'http://static.lolesports.com/teams/AST-FullonLight.png', 'http://static.lolesports.com/teams/AstralisAST.png', 33); +INSERT INTO public.team VALUES (16, 101383793572656373, 'excel', 'EXCEL', 'XL', 'http://static.lolesports.com/teams/Excel_FullColor2.png', 'http://static.lolesports.com/teams/Excel_FullColor1.png', 'http://static.lolesports.com/teams/ExcelXL.png', 33); +INSERT INTO public.team VALUES (17, 101383793574360315, 'rogue', 'Rogue', 'RGE', 'http://static.lolesports.com/teams/1631819715136_rge-2021-worlds.png', NULL, 'http://static.lolesports.com/teams/1632941190948_RGE.png', 33); +INSERT INTO public.team VALUES (18, 101388912911039804, 'thunder-talk-gaming', 'Thunder Talk Gaming', 'TT', 'http://static.lolesports.com/teams/TT-FullonDark.png', 'http://static.lolesports.com/teams/TT-FullonLight.png', 'http://static.lolesports.com/teams/TTTT.png', 35); +INSERT INTO public.team VALUES (19, 101388912914513220, 'victory-five', 'Victory Five', 'V5', 'http://static.lolesports.com/teams/1592592149333_VictoryFiveV5-01-FullonDark.png', 'http://static.lolesports.com/teams/1592592149336_VictoryFiveV5-03-FullonLight.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/victory-five-ha9mq1rv.png', 35); +INSERT INTO public.team VALUES (20, 101422616509070746, 'galatasaray-espor', 'Galatasaray Espor', 'GS', 'http://static.lolesports.com/teams/1631820533570_galatasaray-2021-worlds.png', 'http://static.lolesports.com/teams/1631820533572_galatasaray-2021-worlds.png', 'http://static.lolesports.com/teams/1632941006301_GalatasarayGS.png', 39); +INSERT INTO public.team VALUES (21, 101428372598668846, 'burning-core', 'Burning Core', 'BC', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/burning-core-7q0431w1.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/burning-core-8a63k0iu.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/burning-core-fnmfa2td.png', 40); +INSERT INTO public.team VALUES (22, 101428372600307248, 'rascal-jester', 'Rascal Jester', 'RJ', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/rascal-jester-e0g6cud0.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/rascal-jester-g32ay08v.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/rascal-jester-guqjh8kb.png', 40); +INSERT INTO public.team VALUES (23, 101428372602011186, 'v3-esports', 'V3 Esports', 'V3', 'http://static.lolesports.com/teams/v3_500x500.png', 'http://static.lolesports.com/teams/v3_500x500.png', NULL, 40); +INSERT INTO public.team VALUES (24, 101428372603715124, 'crest-gaming-act', 'Crest Gaming Act', 'CGA', 'http://static.lolesports.com/teams/1630058341510_cga_512px.png', 'http://static.lolesports.com/teams/1630058341513_cga_512px.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/crest-gaming-act-7pkgpqa.png', 40); +INSERT INTO public.team VALUES (25, 101428372605353526, 'sengoku-gaming', 'Sengoku Gaming', 'SG', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/sengoku-gaming-ikyxjlfn.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/sengoku-gaming-gnat0l9c.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/sengoku-gaming-3rd8ifie.png', 40); +INSERT INTO public.team VALUES (26, 101428372607057464, 'axiz', 'AXIZ', 'AXZ', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/axiz-frilmkic.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/axiz-fpemv4d2.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/axiz-9hiwgh3l.png', 40); +INSERT INTO public.team VALUES (27, 101428372830010965, 'alpha-esports', 'Alpha Esports', 'ALF', 'http://static.lolesports.com/teams/1592588479686_AlphaEsportsALF-01-FullonDark.png', 'http://static.lolesports.com/teams/1592588479688_AlphaEsportsALF-03-FullonLight.png', NULL, 4); +INSERT INTO public.team VALUES (28, 101978171843206569, 'vega-squadron', 'Vega Squadron', 'VEG', 'http://static.lolesports.com/teams/vega.png', 'http://static.lolesports.com/teams/vega.png', NULL, 41); +INSERT INTO public.team VALUES (29, 102141671181705193, 'michigan-state-university', 'Michigan State University', 'MSU', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/michigan-state-university-au4vndaf.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/michigan-state-university-c5mv9du0.png', NULL, NULL); +INSERT INTO public.team VALUES (30, 102141671182557163, 'university-of-illinois', 'University of Illinois', 'UI', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/university-of-illinois-bwvscsri.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/university-of-illinois-b3jros5r.png', NULL, NULL); +INSERT INTO public.team VALUES (31, 102141671183409133, 'maryville-university', 'Maryville University', 'MU', 'http://static.lolesports.com/teams/1647541915472_200x200_MU_Logo.png', 'http://static.lolesports.com/teams/1647541915475_200x200_MU_Logo.png', NULL, 28); +INSERT INTO public.team VALUES (32, 102141671185047537, 'uci-esports', 'UCI Esports', 'UCI', 'http://static.lolesports.com/teams/1641604280633_UCI.png', 'http://static.lolesports.com/teams/1641548061305_LOLESPORTSICON.png', NULL, NULL); +INSERT INTO public.team VALUES (33, 102141671185899507, 'university-of-western-ontario', 'University of Western Ontario', 'UWO', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/university-of-western-ontario-9q0nn3lw.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/university-of-western-ontario-6csb5dft.png', NULL, NULL); +INSERT INTO public.team VALUES (34, 102141671186685941, 'university-of-waterloo', 'University of Waterloo', 'UW', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/university-of-waterloo-2wuni11l.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/university-of-waterloo-aghmypqf.png', NULL, NULL); +INSERT INTO public.team VALUES (35, 102141671187668983, 'nc-state-university', 'NC State University', 'NCSU', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/nc-state-university-it42b898.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/nc-state-university-6ey19n1w.png', NULL, NULL); +INSERT INTO public.team VALUES (36, 102235771678061291, 'fastpay-wildcats', 'fastPay Wildcats', 'IW', 'http://static.lolesports.com/teams/fastpay-wildcats.png', 'http://static.lolesports.com/teams/fastpay-wildcats.png', NULL, 39); +INSERT INTO public.team VALUES (37, 102747101565183056, 'nongshim-redforce', 'NongShim REDFORCE', 'NS', 'http://static.lolesports.com/teams/NSFullonDark.png', 'http://static.lolesports.com/teams/NSFullonLight.png', 'http://static.lolesports.com/teams/NongshimRedForceNS.png', 34); +INSERT INTO public.team VALUES (38, 102787200120306562, 'mousesports', 'Mousesports', 'MOUZ', 'http://static.lolesports.com/teams/1639486346996_PRM_MOUZ-FullColorDarkBG.png', 'http://static.lolesports.com/teams/1639486346999_PRM_MOUZ-FullColorDarkBG.png', NULL, NULL); +INSERT INTO public.team VALUES (39, 102787200124959636, 'crvena-zvezda-esports', 'Crvena Zvezda Esports', 'CZV', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/crvena-zvezda-esports-ddtlzzhd.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/crvena-zvezda-esports-ddtlzzhd.png', NULL, 1); +INSERT INTO public.team VALUES (40, 102787200126663579, 'giants', 'Giants', 'GIA', 'http://static.lolesports.com/teams/1641412992057_escudowhite.png', 'http://static.lolesports.com/teams/1641412992058_escudo_black.png', NULL, NULL); +INSERT INTO public.team VALUES (41, 102787200129022886, 'esuba', 'eSuba', 'ESB', 'http://static.lolesports.com/teams/1629209489523_esuba_full_pos.png', 'http://static.lolesports.com/teams/1629209489525_esuba_full_pos.png', NULL, NULL); +INSERT INTO public.team VALUES (42, 102787200130988976, 'asus-rog-elite', 'ASUS ROG Elite', 'ASUS', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/asus-rog-elite-iouou6l.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/asus-rog-elite-cz4z103n.png', NULL, NULL); +INSERT INTO public.team VALUES (43, 102787200132955066, 'for-the-win-esports', 'For The Win Esports', 'FTW', 'http://static.lolesports.com/teams/LPLOL_FTW-Logo1.png', 'http://static.lolesports.com/teams/LPLOL_FTW-Logo1.png', NULL, NULL); +INSERT INTO public.team VALUES (44, 102787200134790084, 'hma-fnatic-rising', 'HMA Fnatic Rising', 'FNCR', 'http://static.lolesports.com/teams/NLC_FNCR-logo.png', 'http://static.lolesports.com/teams/NLC_FNCR-logo.png', NULL, NULL); +INSERT INTO public.team VALUES (45, 102787200136756173, 'berlin-international-gaming', 'Berlin International Gaming', 'BIG', 'http://static.lolesports.com/teams/BIG-Logo-2020-White1.png', 'http://static.lolesports.com/teams/BIG-Logo-2020-White1.png', NULL, 7); +INSERT INTO public.team VALUES (46, 102787200138722262, 'devilsone', 'Devils.One', 'DV1', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/devilsone-bfe3xkh.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/devilsone-dmj5ivct.png', NULL, 6); +INSERT INTO public.team VALUES (47, 102787200143309800, 'ensure', 'eNsure', 'EN', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/ensure-5hi6e2cg.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/ensure-fehdkert.png', NULL, 1); +INSERT INTO public.team VALUES (48, 102787200145472495, 'defusekids', 'Defusekids', 'DKI', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/defusekids-finmimok.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/defusekids-wu2z0pj.png', NULL, NULL); +INSERT INTO public.team VALUES (49, 102787200147504121, 'campus-party-sparks', 'Campus Party Sparks', 'SPK', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/campus-party-sparks-5h2d1rjh.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/campus-party-sparks-72ccff49.png', NULL, NULL); +INSERT INTO public.team VALUES (50, 102787200149928963, 'we-love-gaming', 'We Love Gaming', 'WLG', 'http://static.lolesports.com/teams/WLGlogo.png', 'http://static.lolesports.com/teams/WLGlogo.png', NULL, NULL); +INSERT INTO public.team VALUES (51, 102787200151698443, 'vitalitybee', 'Vitality.Bee', 'VITB', 'http://static.lolesports.com/teams/Vitality-logo-color-outline-rgb.png', 'http://static.lolesports.com/teams/Vitality-logo-color-outline-rgb.png', NULL, 1); +INSERT INTO public.team VALUES (52, 102787200153467923, 'bcn-squad', 'BCN Squad', 'BCN', 'http://static.lolesports.com/teams/SL_BCN-Logo_White.png', 'http://static.lolesports.com/teams/SL_BCN-Logo_Dark.png', NULL, NULL); +INSERT INTO public.team VALUES (53, 102787200155434012, 'jdxl', 'JD|XL', 'JDXL', 'http://static.lolesports.com/teams/1641489535868_jdxl.png', NULL, NULL, 9); +INSERT INTO public.team VALUES (54, 102787200157400101, 'falkn', 'FALKN', 'FKN', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/falkn-j72aqsqk.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/falkn-dhvtpixb.png', NULL, 1); +INSERT INTO public.team VALUES (55, 102787200159169580, 'godsent', 'Godsent', 'GOD', 'http://static.lolesports.com/teams/NLC_GOD-light.png', 'http://static.lolesports.com/teams/NLC_GOD-dark.png', NULL, NULL); +INSERT INTO public.team VALUES (56, 102825747701670848, 'azules-esports', 'Azules Esports', 'UCH', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/azules-esports-ak2khbqa.png', NULL, 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/azules-esports-e8yjxxki.png', NULL); +INSERT INTO public.team VALUES (57, 103461966951059521, 'evil-geniuses', 'Evil Geniuses', 'EG', 'http://static.lolesports.com/teams/1592590374862_EvilGeniusesEG-01-FullonDark.png', 'http://static.lolesports.com/teams/1592590374875_EvilGeniusesEG-03-FullonLight.png', 'http://static.lolesports.com/teams/1590003096057_EvilGeniusesEG.png', 32); +INSERT INTO public.team VALUES (58, 103461966965149786, 'mad-lions', 'MAD Lions', 'MAD', 'http://static.lolesports.com/teams/1631819614211_mad-2021-worlds.png', 'http://static.lolesports.com/teams/1592591395341_MadLionsMAD-03-FullonLight.png', 'http://static.lolesports.com/teams/MAD.png', 33); +INSERT INTO public.team VALUES (59, 103461966971048042, 'eg-academy', 'EG Academy', 'EG', 'http://static.lolesports.com/teams/1592590391188_EvilGeniusesEG-01-FullonDark.png', 'http://static.lolesports.com/teams/1592590391200_EvilGeniusesEG-03-FullonLight.png', 'http://static.lolesports.com/teams/1590003135776_EvilGeniusesEG.png', 28); +INSERT INTO public.team VALUES (60, 103461966975897718, 'imt-academy', 'IMT Academy', 'IMT', 'http://static.lolesports.com/teams/imt-new-color.png', 'http://static.lolesports.com/teams/imt-new-color.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/immortals-academy-hmxmnvhe.png', 28); +INSERT INTO public.team VALUES (61, 103461966981927044, 'dig-academy', 'DIG Academy', 'DIG', 'http://static.lolesports.com/teams/DIG-FullonDark.png', 'http://static.lolesports.com/teams/DIG-FullonLight.png', 'http://static.lolesports.com/teams/DignitasDIG.png', 28); +INSERT INTO public.team VALUES (62, 103461966986776720, 'ultra-prime', 'Ultra Prime', 'UP', 'http://static.lolesports.com/teams/ultraprime.png', 'http://static.lolesports.com/teams/ultraprime.png', NULL, 35); +INSERT INTO public.team VALUES (63, 103495716836203404, '5-ronin', '5 Ronin', '5R', 'http://static.lolesports.com/teams/5R_LOGO.png', 'http://static.lolesports.com/teams/5R_LOGO.png', NULL, 39); +INSERT INTO public.team VALUES (100, 104211666442891296, 'ogaming', 'O''Gaming', 'OGA', 'http://static.lolesports.com/teams/1590143833802_Ays7Gjmu_400x400.jpg', NULL, NULL, NULL); +INSERT INTO public.team VALUES (64, 103495716886587312, 'besiktas', 'Beşiktaş', 'BJK', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/besiktas-e-sports-club-dlw48ntu.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/besiktas-e-sports-club-6ttscu28.png', NULL, 39); +INSERT INTO public.team VALUES (65, 103535282113853330, '5-ronin-akademi', '5 Ronin Akademi', '5R', 'http://static.lolesports.com/teams/5R_LOGO.png', 'http://static.lolesports.com/teams/5R_LOGO.png', NULL, 2); +INSERT INTO public.team VALUES (66, 103535282119620510, 'fukuoka-softbank-hawks-gaming', 'Fukuoka SoftBank HAWKS gaming', 'SHG', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/fukuoka-softbank-hawks-gaming-b99n2uq2.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/fukuoka-softbank-hawks-gaming-4i3ympnq.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/fukuoka-softbank-hawks-gaming-4fl2jmuh.png', 40); +INSERT INTO public.team VALUES (67, 103535282124208038, 'pentanetgg', 'Pentanet.GG', 'PGG', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/pentanetgg-3vnqnv03.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/pentanetgg-3d4g4sbh.png', NULL, 16); +INSERT INTO public.team VALUES (68, 103535282135552642, 'papara-supermassive-blaze-akademi', 'Papara SuperMassive Blaze Akademi', 'SMB', 'http://static.lolesports.com/teams/1628521896643_SMBA_WHITE.png', 'http://static.lolesports.com/teams/1628521896646_SMBA_BLACK.png', NULL, 2); +INSERT INTO public.team VALUES (69, 103535282138043022, 'fenerbahce-espor-akademi', 'Fenerbahçe Espor Akademi', 'FB', 'http://static.lolesports.com/teams/1642680283028_BANPICK_FB.png', 'http://static.lolesports.com/teams/1642680283035_BANPICK_FB.png', NULL, 2); +INSERT INTO public.team VALUES (70, 103535282140533402, 'besiktas-akademi', 'Beşiktaş Akademi', 'BJK', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/besiktas-akademi-6dlbk21d.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/besiktas-akademi-fobrhai9.png', NULL, 2); +INSERT INTO public.team VALUES (71, 103535282143744679, 'dark-passage-akademi', 'Dark Passage Akademi', 'DP', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/dark-passage-akademi-9ehs6q0l.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/dark-passage-akademi-h4x5hq6.png', NULL, 2); +INSERT INTO public.team VALUES (72, 103535282146169523, 'info-yatrm-aurora-akademi', 'Info Yatırım Aurora Akademi', 'AUR', 'http://static.lolesports.com/teams/1642680351930_BANPICK_AUR.png', 'http://static.lolesports.com/teams/1642680351936_BANPICK_AUR.png', NULL, 2); +INSERT INTO public.team VALUES (73, 103535282148790975, 'galakticos-akademi', 'GALAKTICOS Akademi', 'GAL', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/galakticos-akademi-4x1ww2pc.png', 'https://lolstatic-a.akamaihd.net/esports-assets/production/team/galakticos-akademi-dv3kn0pg.png', NULL, 2); +INSERT INTO public.team VALUES (74, 103535282158162659, 'fastpay-wildcats-akademi', 'fastPay Wildcats Akademi', 'IW', 'http://static.lolesports.com/teams/1582880891336_IW.png', 'http://static.lolesports.com/teams/1582880891351_IW.png', NULL, 2); +INSERT INTO public.team VALUES (75, 103877554248683116, 'schalke-04-evolution', 'Schalke 04 Evolution', 'S04E', 'http://static.lolesports.com/teams/S04_Standard_Logo1.png', 'http://static.lolesports.com/teams/S04_Standard_Logo1.png', NULL, NULL); +INSERT INTO public.team VALUES (76, 103877589042434434, 'gamerlegion', 'GamerLegion', 'GL', 'http://static.lolesports.com/teams/1585046217463_220px-Team_GamerLegionlogo_square.png', NULL, NULL, 1); +INSERT INTO public.team VALUES (77, 103877625775457850, 'movistar-riders', 'Movistar Riders', 'MRS', 'http://static.lolesports.com/teams/1585046777741_220px-Movistar_Riderslogo_square.png', NULL, NULL, NULL); +INSERT INTO public.team VALUES (78, 103877675241047720, 'ldlc-ol', 'LDLC OL', 'LDLC', 'http://static.lolesports.com/teams/LFL-LDLC-logo.png', 'http://static.lolesports.com/teams/LFL-LDLC-logo.png', NULL, 1); +INSERT INTO public.team VALUES (79, 103877737868887783, 'saim-se', 'SAIM SE', 'SSB', 'http://static.lolesports.com/teams/1585048488568_220px-SAIM_SElogo_square.png', 'http://static.lolesports.com/teams/1585048488582_220px-SAIM_SElogo_square.png', NULL, NULL); +INSERT INTO public.team VALUES (80, 103877756742242918, 'racoon', 'Racoon', 'RCN', 'http://static.lolesports.com/teams/1585048776551_220px-Racoon_(Italian_Team)logo_square.png', 'http://static.lolesports.com/teams/1585048776564_220px-Racoon_(Italian_Team)logo_square.png', NULL, NULL); +INSERT INTO public.team VALUES (81, 103877774634323825, 'ydn-gamers', 'YDN Gamers', 'YDN', 'http://static.lolesports.com/teams/1587638409857_LOGO_YDN_-trasp.png', 'http://static.lolesports.com/teams/1587638409876_LOGO_YDN_-trasp.png', NULL, NULL); +INSERT INTO public.team VALUES (82, 103877879209300619, 'vipers-inc', 'Vipers Inc', 'VIP', 'http://static.lolesports.com/teams/1585050644953_220px-Vipers_Inclogo_square.png', 'http://static.lolesports.com/teams/1585050644968_220px-Vipers_Inclogo_square.png', NULL, NULL); +INSERT INTO public.team VALUES (83, 103877891572305836, 'team-singularity', 'Team Singularity', 'SNG', 'http://static.lolesports.com/teams/NLC_SNG-light.png', 'http://static.lolesports.com/teams/NLC_SNG-logo.png', NULL, 9); +INSERT INTO public.team VALUES (84, 103877908090914662, 'kenty', 'Kenty', 'KEN', 'http://static.lolesports.com/teams/1585051086000_220px-Kentylogo_square.png', 'http://static.lolesports.com/teams/1585051086014_220px-Kentylogo_square.png', NULL, NULL); +INSERT INTO public.team VALUES (85, 103877925817094140, 'pigsports', 'PIGSPORTS', 'PIG', 'http://static.lolesports.com/teams/PIGSPORTS_PIG-Logo1.png', 'http://static.lolesports.com/teams/PIGSPORTS_PIG-Logo1.png', NULL, NULL); +INSERT INTO public.team VALUES (86, 103877951616192529, 'cyber-gaming', 'Cyber Gaming', 'CG', 'http://static.lolesports.com/teams/1585051749524_220px-Cyber_Gaminglogo_square.png', 'http://static.lolesports.com/teams/1585051749529_220px-Cyber_Gaminglogo_square.png', NULL, NULL); +INSERT INTO public.team VALUES (87, 103877976717529187, 'intrepid-fox-gaming', 'Intrepid Fox Gaming', 'IF', 'http://static.lolesports.com/teams/1585052132267_220px-Intrepid_Fox_Gaminglogo_square.png', 'http://static.lolesports.com/teams/1585052132281_220px-Intrepid_Fox_Gaminglogo_square.png', NULL, NULL); +INSERT INTO public.team VALUES (88, 103878020539746273, 'egn-esports', 'EGN Esports', 'EGN', 'http://static.lolesports.com/teams/LPLOL_EGN-Logo1.png', 'http://static.lolesports.com/teams/LPLOL_EGN-Logo1.png', NULL, NULL); +INSERT INTO public.team VALUES (89, 103935421249833954, 'mad-lions-madrid', 'MAD Lions Madrid', 'MADM', 'http://static.lolesports.com/teams/SL_MADM-Logo_white.png', 'http://static.lolesports.com/teams/SL_MADM-Logo_dark.png', NULL, 5); +INSERT INTO public.team VALUES (90, 103935446548920777, 'misfits-premier', 'Misfits Premier', 'MSFP', 'http://static.lolesports.com/teams/LFL-MSFP-logo.png', 'http://static.lolesports.com/teams/LFL-MSFP-logo.png', NULL, NULL); +INSERT INTO public.team VALUES (91, 103935468920814040, 'gamersorigin', 'GamersOrigin', 'GO', 'http://static.lolesports.com/teams/1588178480033_logoGO_2020_G_Blanc.png', 'http://static.lolesports.com/teams/1588178480035_logoGO_2020_G_Noir.png', NULL, 11); +INSERT INTO public.team VALUES (92, 103935523328473675, 'k1ck-neosurf', 'K1CK Neosurf', 'K1', 'http://static.lolesports.com/teams/1585930223604_K1ck_Neosurflogo_square.png', NULL, NULL, NULL); +INSERT INTO public.team VALUES (93, 103935530333072898, 'ago-rogue', 'AGO Rogue', 'RGO', 'http://static.lolesports.com/teams/1585930330127_AGO_ROGUElogo_square.png', NULL, NULL, 1); +INSERT INTO public.team VALUES (94, 103935567188806885, 'energypot-wizards', 'Energypot Wizards', 'EWIZ', 'http://static.lolesports.com/teams/1585930892362_Energypot_Wizardslogo_square.png', NULL, NULL, NULL); +INSERT INTO public.team VALUES (95, 103935642731826448, 'sector-one', 'Sector One', 'S1', 'http://static.lolesports.com/teams/1641288621852_1024x1024_sector_one_nameless_white.png', 'http://static.lolesports.com/teams/1641288621854_1024x1024_sector_one_nameless_black.png', NULL, 19); +INSERT INTO public.team VALUES (96, 103963647433204351, 'm19', 'M19', 'M19', 'http://static.lolesports.com/teams/1586359360406_M19logo_square.png', NULL, NULL, NULL); +INSERT INTO public.team VALUES (97, 103963715924353674, 'dragon-army', 'Dragon Army', 'DA', 'http://static.lolesports.com/teams/1586360405423_440px-Dragon_Armylogo_square.png', NULL, NULL, 41); +INSERT INTO public.team VALUES (98, 103963753080578719, 'crowcrowd-moscow', 'CrowCrowd Moscow', 'CC', 'http://static.lolesports.com/teams/Logo_CC.png', NULL, NULL, 41); +INSERT INTO public.team VALUES (99, 104202382255290736, 'rensga', 'RENSGA', 'RNS', 'http://static.lolesports.com/teams/LogoRensgaEsports.png', 'http://static.lolesports.com/teams/LogoRensgaEsports.png', 'http://static.lolesports.com/teams/RensgaRNS.png', 37); + + +-- Values for tournament table +INSERT INTO public.tournament VALUES (1, 107893386210553711, 'european_masters_spring_2022_main_event', '2022-04-13', '2022-05-08', 1); +INSERT INTO public.tournament VALUES (2, 107530554766055254, 'lla_opening_2022', '2022-01-28', '2022-04-17', 3); +INSERT INTO public.tournament VALUES (3, 107693721179065689, 'pcs_2022_spring', '2022-02-11', '2022-04-18', 4); +INSERT INTO public.tournament VALUES (4, 107468241207873310, 'superliga_2022_spring', '2022-01-09', '2022-05-01', 5); +INSERT INTO public.tournament VALUES (5, 107416436272657995, 'ultraliga_2022_spring', '2022-01-01', '2022-05-01', 6); +INSERT INTO public.tournament VALUES (6, 107417741193036913, 'prime_2022_spring', '2022-01-01', '2022-05-01', 7); +INSERT INTO public.tournament VALUES (7, 107457033672415830, 'pg_spring', '2022-01-17', '2022-05-01', 8); +INSERT INTO public.tournament VALUES (8, 107417432877679361, 'nlc_2022_spring', '2022-01-01', '2022-05-15', 9); +INSERT INTO public.tournament VALUES (9, 107468370558963709, 'lfl_2022_spring', '2022-01-09', '2022-05-01', 11); +INSERT INTO public.tournament VALUES (10, 107565607659994755, 'cblol_academy_2022', '2022-01-24', '2022-04-18', 15); +INSERT INTO public.tournament VALUES (11, 107439320897210747, 'lco_spring_2022', '2022-01-23', '2022-04-29', 16); +INSERT INTO public.tournament VALUES (12, 107563481236862420, 'eslol_spring', '2022-01-16', '2022-05-01', 19); +INSERT INTO public.tournament VALUES (13, 107682708465517027, 'discover_volcano_league_opening_2022', '2022-01-25', '2022-04-16', 22); +INSERT INTO public.tournament VALUES (14, 107728324355999617, 'master_flow_league_opening_2022', '2022-01-26', '2022-04-24', 24); +INSERT INTO public.tournament VALUES (15, 107677841285321565, 'honor_league_opening_2022', '2022-01-24', '2022-04-16', 25); +INSERT INTO public.tournament VALUES (16, 107921288851375933, 'proving_grounds_spring_2022', '2022-03-16', '2022-04-16', 28); +INSERT INTO public.tournament VALUES (17, 108097587668586485, 'tft_emea_lcq_2022', '2022-04-16', '2022-04-16', 29); +INSERT INTO public.tournament VALUES (18, 107458367237283414, 'lcs_spring_2022', '2022-02-04', '2022-04-25', 32); +INSERT INTO public.tournament VALUES (19, 107417059262120466, 'lec_2022_spring', '2022-01-01', '2022-05-15', 33); +INSERT INTO public.tournament VALUES (20, 107417779630700437, 'lpl_spring_2022', '2022-01-10', '2022-05-01', 35); +INSERT INTO public.tournament VALUES (21, 107405837336179496, 'cblol_2022_split1', '2022-01-22', '2022-04-23', 37); +INSERT INTO public.tournament VALUES (22, 107417471555810057, 'lcl_spring_2022', '2022-02-11', '2022-04-16', 41); +INSERT INTO public.tournament VALUES (23, 107418086627198298, 'lcs_academy_2022_spring', '2022-01-19', '2022-05-31', 42); From adb63dcce56bd5155e6740a1af86bcae88a203f0 Mon Sep 17 00:00:00 2001 From: onsystem Date: Sat, 22 Jul 2023 20:21:00 +0200 Subject: [PATCH 02/27] mysql-support - first implementation workspace canyon_connection --- .gitignore | 3 +- Cargo.toml | 5 +- canyon_connection/Cargo.toml | 3 + .../src/canyon_database_connector.rs | 95 ++++++++++++++++++- canyon_connection/src/datasources.rs | 41 +++++++- canyon_connection/src/lib.rs | 2 + canyon_crud/Cargo.toml | 3 + canyon_crud/src/crud.rs | 4 + canyon_macros/Cargo.toml | 2 + canyon_migrations/Cargo.toml | 3 + canyon_migrations/src/migrations/handler.rs | 4 + canyon_migrations/src/migrations/memory.rs | 2 + canyon_migrations/src/migrations/processor.rs | 41 ++++++-- tests/Cargo.toml | 1 + tests/canyon.toml | 12 +++ tests/constants.rs | 2 + 16 files changed, 206 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index a38bca38..056b3728 100755 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ Cargo.lock canyon_tester/ macro_utils.rs .vscode/ -postgres-data/ \ No newline at end of file +postgres-data/ +mysql-data/ \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 341a28dd..557cfe1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ members = [ "canyon_entities", "canyon_migrations", "canyon_macros", - "tests" ] @@ -31,6 +30,8 @@ canyon_macros = { workspace = true, path = "canyon_macros" } # To be marked as opt deps tokio-postgres = { workspace = true, optional = true } tiberius = { workspace = true, optional = true } +mysql_async = { workspace = true, optional = true } + [workspace.dependencies] canyon_crud = { version = "0.4.2", path = "canyon_crud" } @@ -43,6 +44,7 @@ tokio = { version = "1.27.0", features = ["full"] } tokio-util = { version = "0.7.4", features = ["compat"] } tokio-postgres = { version = "0.7.2", features = ["with-chrono-0_4"] } tiberius = { version = "0.12.1", features = ["tds73", "chrono", "integrated-auth-gssapi"] } +mysql_async = { version = "0.32.2"} chrono = { version = "0.4", features = ["serde"] } # Just from TP better? serde = { version = "1.0.138", features = ["derive"] } @@ -73,4 +75,5 @@ description = "A Rust ORM and QueryBuilder" [features] postgres = ["tokio-postgres", "canyon_connection/postgres", "canyon_crud/postgres", "canyon_migrations/postgres", "canyon_macros/postgres"] mssql = ["tiberius", "canyon_connection/mssql", "canyon_crud/mssql", "canyon_migrations/mssql", "canyon_macros/mssql"] +mysql = ["mysql_async", "canyon_connection/mysql", "canyon_crud/mysql", "canyon_migrations/mysql", "canyon_macros/mysql"] migrations = ["canyon_migrations", "canyon_macros/migrations"] diff --git a/canyon_connection/Cargo.toml b/canyon_connection/Cargo.toml index fd37fd4e..e22d4b10 100644 --- a/canyon_connection/Cargo.toml +++ b/canyon_connection/Cargo.toml @@ -15,6 +15,7 @@ tokio-util = { workspace = true } tokio-postgres = { workspace = true, optional = true } tiberius = { workspace = true, optional = true } +mysql_async = { workspace = true, optional = true } futures = { workspace = true } indexmap = { workspace = true } @@ -28,3 +29,5 @@ walkdir = { workspace = true } [features] postgres = ["tokio-postgres"] mssql = ["tiberius", "async-std"] +mysql = ["mysql_async"] + diff --git a/canyon_connection/src/canyon_database_connector.rs b/canyon_connection/src/canyon_database_connector.rs index 7196e948..764f7e6c 100644 --- a/canyon_connection/src/canyon_database_connector.rs +++ b/canyon_connection/src/canyon_database_connector.rs @@ -2,6 +2,8 @@ use serde::Deserialize; #[cfg(feature = "mssql")] use async_std::net::TcpStream; +#[cfg(feature = "mysql")] +use mysql_async::Conn; #[cfg(feature = "mssql")] use tiberius::{AuthMethod, Config}; #[cfg(feature = "postgres")] @@ -18,6 +20,9 @@ pub enum DatabaseType { #[serde(alias = "sqlserver", alias = "mssql")] #[cfg(feature = "mssql")] SqlServer, + #[serde(alias = "mysql")] + #[cfg(feature = "mysql")] + MySQL, } /// A connection with a `PostgreSQL` database @@ -33,6 +38,12 @@ pub struct SqlServerConnection { pub client: &'static mut tiberius::Client, } +/// A connection with a `Mysql` database +#[cfg(feature = "mysql")] +pub struct MysqlConnection { + pub client: Conn, //TODO this is Connection with server but it could be interesting to use Pool +} + /// The Canyon database connection handler. When the client's program /// starts, Canyon gets the information about the desired datasources, /// process them and generates a pool of 1 to 1 database connection for @@ -42,6 +53,8 @@ pub enum DatabaseConnection { Postgres(PostgreSqlConnection), #[cfg(feature = "mssql")] SqlServer(SqlServerConnection), + #[cfg(feature = "mysql")] + MySQL(MysqlConnection), } unsafe impl Send for DatabaseConnection {} @@ -64,6 +77,10 @@ impl DatabaseConnection { crate::datasources::Auth::SqlServer(_) => { panic!("Found SqlServer auth configuration for a PostgreSQL datasource") } + #[cfg(feature = "mysql")] + crate::datasources::Auth::MySQL(_) => { + panic!("Found MySql auth configuration for a PostgreSQL datasource") + } }; let (new_client, new_connection) = tokio_postgres::connect( &format!( @@ -109,6 +126,10 @@ impl DatabaseConnection { } crate::datasources::SqlServerAuth::Integrated => AuthMethod::Integrated, }, + #[cfg(feature = "mysql")] + crate::datasources::Auth::MySQL(_) => { + panic!("Found PostgreSQL auth configuration for a SqlServer database") + } }); // on production, it is not a good idea to do this. We should upgrade @@ -136,6 +157,41 @@ impl DatabaseConnection { )), })) } + #[cfg(feature = "mysql")] + DatabaseType::MySQL => { + let (user, password) = match &datasource.auth { + #[cfg(feature = "mssql")] + crate::datasources::Auth::SqlServer(_) => { + panic!("Found SqlServer auth configuration for a PostgreSQL datasource") + } + #[cfg(feature = "postgres")] + crate::datasources::Auth::Postgres(_) => { + panic!("Found MySql auth configuration for a PostgreSQL datasource") + } + #[cfg(feature = "mysql")] + crate::datasources::Auth::MySQL(mysql_auth) => match mysql_auth { + crate::datasources::MySQLAuth::Basic { username, password } => { + (username, password) + } + }, + }; + + //TODO add options to optionals params in url + + let url = format!( + "mysql://{}:{}@{}:{}/{}", + user, + password, + datasource.properties.host, + datasource.properties.port.unwrap_or_default(), + datasource.properties.db_name + ); + + let mysql_connection = Conn::from_url(url).await?; + Ok(DatabaseConnection::MySQL(MysqlConnection { + client: { mysql_connection }, + })) + } } } @@ -143,7 +199,7 @@ impl DatabaseConnection { pub fn postgres_connection(&self) -> &PostgreSqlConnection { match self { DatabaseConnection::Postgres(conn) => conn, - #[cfg(all(feature = "postgres", feature = "mssql"))] + #[cfg(all(feature = "postgres", feature = "mssql", feature = "mysql"))] _ => panic!(), } } @@ -152,7 +208,16 @@ impl DatabaseConnection { pub fn sqlserver_connection(&mut self) -> &mut SqlServerConnection { match self { DatabaseConnection::SqlServer(conn) => conn, - #[cfg(all(feature = "postgres", feature = "mssql"))] + #[cfg(all(feature = "postgres", feature = "mssql", feature = "mysql"))] + _ => panic!(), + } + } + + #[cfg(feature = "mysql")] + pub fn mysql_connection(&mut self) -> &mut MysqlConnection { + match self { + DatabaseConnection::MySQL(conn) => conn, + #[cfg(all(feature = "postgres", feature = "mssql", feature = "mysql"))] _ => panic!(), } } @@ -166,13 +231,14 @@ mod database_connection_handler { /// Tests the behaviour of the `DatabaseType::from_datasource(...)` #[test] fn check_from_datasource() { - #[cfg(all(feature = "postgres", feature = "mssql"))] + #[cfg(all(feature = "postgres", feature = "mssql", feature = "mysql"))] { const CONFIG_FILE_MOCK_ALT_ALL: &str = r#" [canyon_sql] datasources = [ {name = 'PostgresDS', auth = { postgresql = { basic = { username = "postgres", password = "postgres" } } }, properties.host = 'localhost', properties.db_name = 'triforce', properties.migrations='enabled' }, - {name = 'SqlServerDS', auth = { sqlserver = { basic = { username = "sa", password = "SqlServer-10" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' } + {name = 'SqlServerDS', auth = { sqlserver = { basic = { username = "sa", password = "SqlServer-10" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' }, + {name = 'MysqlDS', auth = { mysql = { basic = { username = "root", password = "root" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' } ] "#; let config: CanyonSqlConfig = toml::from_str(CONFIG_FILE_MOCK_ALT_ALL) @@ -185,6 +251,10 @@ mod database_connection_handler { config.canyon_sql.datasources[1].get_db_type(), DatabaseType::SqlServer ); + assert_eq!( + config.canyon_sql.datasources[2].get_db_type(), + DatabaseType::MySQL + ); } #[cfg(feature = "postgres")] @@ -218,5 +288,22 @@ mod database_connection_handler { DatabaseType::SqlServer ); } + + #[cfg(feature = "mysql")] + { + const CONFIG_FILE_MOCK_ALT_MYSQL: &str = r#" + [canyon_sql] + datasources = [ + {name = 'MysqlDS', auth = { mysql = { basic = { username = "root", password = "root" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' } + ] + "#; + + let config: CanyonSqlConfig = toml::from_str(CONFIG_FILE_MOCK_ALT_MYSQL) + .expect("A failure happened retrieving the [canyon_sql] section"); + assert_eq!( + config.canyon_sql.datasources[0].get_db_type(), + DatabaseType::MySQL + ); + } } } diff --git a/canyon_connection/src/datasources.rs b/canyon_connection/src/datasources.rs index 9571c343..1eba8fc7 100644 --- a/canyon_connection/src/datasources.rs +++ b/canyon_connection/src/datasources.rs @@ -11,7 +11,7 @@ fn load_ds_config_from_array() { [canyon_sql] datasources = [ {name = 'PostgresDS', auth = { postgresql = { basic = { username = "postgres", password = "postgres" } } }, properties.host = 'localhost', properties.db_name = 'triforce', properties.migrations='enabled' }, - ] + ] "#; let config: CanyonSqlConfig = toml::from_str(CONFIG_FILE_MOCK_ALT_PG) .expect("A failure happened retrieving the [canyon_sql] section"); @@ -64,6 +64,33 @@ fn load_ds_config_from_array() { assert_eq!(ds_2.auth, Auth::SqlServer(SqlServerAuth::Integrated)); } + #[cfg(feature = "mysql")] + { + const CONFIG_FILE_MOCK_ALT_MYSQL: &str = r#" + [canyon_sql] + datasources = [ + {name = 'MysqlDS', auth = { mysql = { basic = { username = "root", password = "root" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' } + ] + "#; + let config: CanyonSqlConfig = toml::from_str(CONFIG_FILE_MOCK_ALT_MYSQL) + .expect("A failure happened retrieving the [canyon_sql] section"); + + let ds_1 = &config.canyon_sql.datasources[0]; + + assert_eq!(ds_1.name, "MysqlDS"); + assert_eq!(ds_1.get_db_type(), DatabaseType::MySQL); + assert_eq!( + ds_1.auth, + Auth::MySQL(MySQLAuth::Basic { + username: "root".to_string(), + password: "root".to_string() + }) + ); + assert_eq!(ds_1.properties.host, "192.168.0.250.1"); + assert_eq!(ds_1.properties.port, Some(3340)); + assert_eq!(ds_1.properties.db_name, "triforce2"); + assert_eq!(ds_1.properties.migrations, Some(Migrations::Disabled)); + } } /// #[derive(Deserialize, Debug, Clone)] @@ -90,6 +117,8 @@ impl DatasourceConfig { Auth::Postgres(_) => DatabaseType::PostgreSql, #[cfg(feature = "mssql")] Auth::SqlServer(_) => DatabaseType::SqlServer, + #[cfg(feature = "postgres")] + Auth::MySQL(_) => DatabaseType::MySQL, } } } @@ -102,6 +131,9 @@ pub enum Auth { #[serde(alias = "SqlServer", alias = "sqlserver", alias = "mssql")] #[cfg(feature = "mssql")] SqlServer(SqlServerAuth), + #[serde(alias = "MYSQL", alias = "mysql", alias = "MySQL")] + #[cfg(feature = "mysql")] + MySQL(MySQLAuth), } #[derive(Deserialize, Debug, Clone, PartialEq)] @@ -120,6 +152,13 @@ pub enum SqlServerAuth { Integrated, } +#[derive(Deserialize, Debug, Clone, PartialEq)] +#[cfg(feature = "mysql")] +pub enum MySQLAuth { + #[serde(alias = "Basic", alias = "basic")] + Basic { username: String, password: String }, +} + #[derive(Deserialize, Debug, Clone)] pub struct DatasourceProperties { pub host: String, diff --git a/canyon_connection/src/lib.rs b/canyon_connection/src/lib.rs index fed9f31f..2723e201 100644 --- a/canyon_connection/src/lib.rs +++ b/canyon_connection/src/lib.rs @@ -2,6 +2,8 @@ pub extern crate async_std; pub extern crate futures; pub extern crate lazy_static; +#[cfg(feature = "mysql")] +pub extern crate mysql_async; #[cfg(feature = "mssql")] pub extern crate tiberius; pub extern crate tokio; diff --git a/canyon_crud/Cargo.toml b/canyon_crud/Cargo.toml index 123a44fe..13e7e8af 100644 --- a/canyon_crud/Cargo.toml +++ b/canyon_crud/Cargo.toml @@ -12,6 +12,8 @@ description.workspace = true [dependencies] tokio-postgres = { workspace = true, optional = true } tiberius = { workspace = true, optional = true } +mysql_async = { workspace = true, optional = true } + chrono = { workspace = true } async-trait = { workspace = true } @@ -20,3 +22,4 @@ canyon_connection = { workspace = true } [features] postgres = ["tokio-postgres", "canyon_connection/postgres"] mssql = ["tiberius", "canyon_connection/mssql"] +mysql = ["mysql_async", "canyon_connection/mysql"] diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index f5c6d37e..8185a0b2 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -52,6 +52,10 @@ pub trait Transaction { ) .await } + #[cfg(feature = "mssql")] + DatabaseConnection::MySQL(_) => { + todo!("Pending to implement") + } } } } diff --git a/canyon_macros/Cargo.toml b/canyon_macros/Cargo.toml index 763fde8d..8b8a2852 100755 --- a/canyon_macros/Cargo.toml +++ b/canyon_macros/Cargo.toml @@ -27,4 +27,6 @@ canyon_migrations = { workspace = true, optional = true } [features] postgres = ["canyon_connection/postgres", "canyon_crud/postgres", "canyon_migrations/postgres"] mssql = ["canyon_connection/mssql", "canyon_crud/mssql", "canyon_migrations/mssql"] +mysql = ["canyon_connection/mysql", "canyon_crud/mysql", "canyon_migrations/mysql"] + migrations = ["canyon_migrations"] diff --git a/canyon_migrations/Cargo.toml b/canyon_migrations/Cargo.toml index ba353b76..39211c00 100644 --- a/canyon_migrations/Cargo.toml +++ b/canyon_migrations/Cargo.toml @@ -17,6 +17,7 @@ canyon_entities = { workspace = true } tokio = { workspace = true } tokio-postgres = { workspace = true, optional = true } tiberius = { workspace = true, optional = true } +mysql_async = { workspace = true, optional = true } async-trait = { workspace = true } @@ -30,3 +31,5 @@ syn = { version = "1.0.86", features = ["full", "parsing"] } # TODO Pending to r [features] postgres = ["tokio-postgres", "canyon_connection/postgres", "canyon_crud/postgres"] mssql = ["tiberius", "canyon_connection/mssql", "canyon_crud/mssql"] +mysql = ["mysql_async", "canyon_connection/mysql", "canyon_crud/mysql"] + diff --git a/canyon_migrations/src/migrations/handler.rs b/canyon_migrations/src/migrations/handler.rs index 24dfb1c4..3d00da8b 100644 --- a/canyon_migrations/src/migrations/handler.rs +++ b/canyon_migrations/src/migrations/handler.rs @@ -94,6 +94,8 @@ impl Migrations { DatabaseType::PostgreSql => constants::postgresql_queries::FETCH_PUBLIC_SCHEMA, #[cfg(feature = "mssql")] DatabaseType::SqlServer => constants::mssql_queries::FETCH_PUBLIC_SCHEMA, + #[cfg(feature = "mysql")] + DatabaseType::MySQL => todo!("Not implemented fetch database in mysql"), }; Self::query(query, [], datasource_name) @@ -291,5 +293,7 @@ fn check_for_table_name( DatabaseType::PostgreSql => table.table_name == res_row.get_postgres::<&str>("table_name"), #[cfg(feature = "mssql")] DatabaseType::SqlServer => table.table_name == res_row.get_mssql::<&str>("table_name"), + #[cfg(feature = "mysql")] + DatabaseType::MySQL => todo!(), } } diff --git a/canyon_migrations/src/migrations/memory.rs b/canyon_migrations/src/migrations/memory.rs index 1d822fd1..80fbe3ad 100644 --- a/canyon_migrations/src/migrations/memory.rs +++ b/canyon_migrations/src/migrations/memory.rs @@ -248,6 +248,8 @@ impl CanyonMemory { DatabaseType::PostgreSql => constants::postgresql_queries::CANYON_MEMORY_TABLE, #[cfg(feature = "mssql")] DatabaseType::SqlServer => constants::mssql_queries::CANYON_MEMORY_TABLE, + #[cfg(feature = "mysql")] + DatabaseType::MySQL => todo!("Memory table in mysql not implemented"), }; Self::query(query, [], datasource_name) diff --git a/canyon_migrations/src/migrations/processor.rs b/canyon_migrations/src/migrations/processor.rs index 425c1b0d..aee9a89e 100644 --- a/canyon_migrations/src/migrations/processor.rs +++ b/canyon_migrations/src/migrations/processor.rs @@ -807,7 +807,9 @@ impl DatabaseOperation for TableOperation { .join(", ") ) .replace('"', "") - } + }, + #[cfg(feature = "mysql")] DatabaseType::MySQL => todo!() + } } @@ -830,7 +832,9 @@ impl DatabaseOperation for TableOperation { be an allowed behaviour for now, only with the table_name parameter on the CanyonEntity annotation. */ - format!("exec sp_rename '{old_table_name}', '{new_table_name}';") + format!("exec sp_rename '{old_table_name}', '{new_table_name}';"), + #[cfg(feature = "mysql")] DatabaseType::MySQL => todo!() + } } @@ -848,7 +852,9 @@ impl DatabaseOperation for TableOperation { FOREIGN KEY ({_column_foreign_key}) REFERENCES {_table_to_reference} ({_column_to_reference});" ), #[cfg(feature = "mssql")] DatabaseType::SqlServer => - todo!("[MS-SQL -> Operation still won't supported by Canyon for Sql Server]") + todo!("[MS-SQL -> Operation still won't supported by Canyon for Sql Server]"), + #[cfg(feature = "mysql")] DatabaseType::MySQL => todo!() + } } @@ -859,7 +865,9 @@ impl DatabaseOperation for TableOperation { "ALTER TABLE {_table_with_foreign_key} DROP CONSTRAINT {_constraint_name};", ), #[cfg(feature = "mssql")] DatabaseType::SqlServer => - todo!("[MS-SQL -> Operation still won't supported by Canyon for Sql Server]") + todo!("[MS-SQL -> Operation still won't supported by Canyon for Sql Server]"), + #[cfg(feature = "mysql")] DatabaseType::MySQL => todo!() + } } @@ -871,7 +879,9 @@ impl DatabaseOperation for TableOperation { _entity_field.field_name ), #[cfg(feature = "mssql")] DatabaseType::SqlServer => - todo!("[MS-SQL -> Operation still won't supported by Canyon for Sql Server]") + todo!("[MS-SQL -> Operation still won't supported by Canyon for Sql Server]"), + #[cfg(feature = "mysql")] DatabaseType::MySQL => todo!() + } } @@ -880,7 +890,9 @@ impl DatabaseOperation for TableOperation { #[cfg(feature = "postgres")] DatabaseType::PostgreSql => format!("ALTER TABLE {table_name} DROP CONSTRAINT {primary_key_name} CASCADE;"), #[cfg(feature = "mssql")] DatabaseType::SqlServer => - format!("ALTER TABLE {table_name} DROP CONSTRAINT {primary_key_name} CASCADE;") + format!("ALTER TABLE {table_name} DROP CONSTRAINT {primary_key_name} CASCADE;"), + #[cfg(feature = "mysql")] DatabaseType::MySQL => todo!() + } } }; @@ -932,7 +944,9 @@ impl DatabaseOperation for ColumnOperation { table_name, entity_field.field_name, to_sqlserver_syntax(entity_field) - ) + ), + #[cfg(feature = "mysql")] DatabaseType::MySQL => todo!() + } ColumnOperation::DeleteColumn(table_name, column_name) => { // TODO Check if operation for SQL server is different @@ -946,7 +960,10 @@ impl DatabaseOperation for ColumnOperation { _entity_field.field_name, to_postgres_alter_syntax(_entity_field) ), #[cfg(feature = "mssql")] DatabaseType::SqlServer => - todo!("[MS-SQL -> Operation still won't supported by Canyon for Sql Server]") + todo!("[MS-SQL -> Operation still won't supported by Canyon for Sql Server]"), + #[cfg(feature = "mysql")] DatabaseType::MySQL => todo!() + + } ColumnOperation::AlterColumnDropNotNull(table_name, entity_field) => match db_type { @@ -956,7 +973,9 @@ impl DatabaseOperation for ColumnOperation { format!( "ALTER TABLE \"{table_name}\" ALTER COLUMN {} {} NULL", entity_field.field_name, to_sqlserver_alter_syntax(entity_field) - ) + ), + #[cfg(feature = "mysql")] DatabaseType::MySQL => todo!() + } #[cfg(feature = "mssql")] ColumnOperation::DropNotNullBeforeDropColumn(table_name, column_name, column_datatype) => format!( @@ -982,7 +1001,9 @@ impl DatabaseOperation for ColumnOperation { "ALTER TABLE \"{table_name}\" ALTER COLUMN {} {} NOT NULL", entity_field.field_name, to_sqlserver_alter_syntax(entity_field) - ) + ), + #[cfg(feature = "mysql")] DatabaseType::MySQL => todo!() + } } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index da6b0dfc..ef9ee7f0 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -14,3 +14,4 @@ path = "canyon_integration_tests.rs" [features] postgres = ["canyon_sql/postgres"] mssql = ["canyon_sql/mssql"] +mysql = ["canyon_sql/mysql"] \ No newline at end of file diff --git a/tests/canyon.toml b/tests/canyon.toml index 0b0614a4..e31be9a2 100644 --- a/tests/canyon.toml +++ b/tests/canyon.toml @@ -22,3 +22,15 @@ sqlserver = { basic = { username = 'sa', password = 'SqlServer-10' } } host = 'localhost' port = 1434 db_name = 'master' + + +[[canyon_sql.datasources]] +name = 'mysql_docker' + +[canyon_sql.datasources.auth] +mysql = { basic = { username = 'root', password = 'root' } } + +[canyon_sql.datasources.properties] +host = 'localhost' +port = 1434 +db_name = 'public' \ No newline at end of file diff --git a/tests/constants.rs b/tests/constants.rs index dd3a268b..26bea3fd 100644 --- a/tests/constants.rs +++ b/tests/constants.rs @@ -4,6 +4,8 @@ pub const PSQL_DS: &str = "postgres_docker"; #[cfg(feature = "mssql")] pub const SQL_SERVER_DS: &str = "sqlserver_docker"; +#[cfg(feature = "mysql")] +pub const MYSQL_DS: &str = "mysql_docker"; #[cfg(all(feature = "postgres", feature = "migrations"))] pub static FETCH_PUBLIC_SCHEMA: &str = From f99f3b34e160b15a2ce3b7edbc6e0105869aee05 Mon Sep 17 00:00:00 2001 From: onsystem Date: Sun, 23 Jul 2023 13:42:25 +0200 Subject: [PATCH 03/27] mysql - change module bounds pending DateTime look problem and implement solution --- Cargo.toml | 6 +- canyon_connection/Cargo.toml | 5 +- .../src/canyon_database_connector.rs | 2 +- canyon_crud/Cargo.toml | 4 +- canyon_crud/src/bounds.rs | 232 +++++++++++++++++- canyon_migrations/Cargo.toml | 4 +- 6 files changed, 237 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 557cfe1a..2ed3e31c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ canyon_macros = { workspace = true, path = "canyon_macros" } tokio-postgres = { workspace = true, optional = true } tiberius = { workspace = true, optional = true } mysql_async = { workspace = true, optional = true } +mysql_common = { workspace = true, optional = true } [workspace.dependencies] @@ -44,7 +45,8 @@ tokio = { version = "1.27.0", features = ["full"] } tokio-util = { version = "0.7.4", features = ["compat"] } tokio-postgres = { version = "0.7.2", features = ["with-chrono-0_4"] } tiberius = { version = "0.12.1", features = ["tds73", "chrono", "integrated-auth-gssapi"] } -mysql_async = { version = "0.32.2"} +mysql_async = { version = "0.32.2" } +mysql_common = { version = "0.30.6", features = [ "chrono" ]} chrono = { version = "0.4", features = ["serde"] } # Just from TP better? serde = { version = "1.0.138", features = ["derive"] } @@ -75,5 +77,5 @@ description = "A Rust ORM and QueryBuilder" [features] postgres = ["tokio-postgres", "canyon_connection/postgres", "canyon_crud/postgres", "canyon_migrations/postgres", "canyon_macros/postgres"] mssql = ["tiberius", "canyon_connection/mssql", "canyon_crud/mssql", "canyon_migrations/mssql", "canyon_macros/mssql"] -mysql = ["mysql_async", "canyon_connection/mysql", "canyon_crud/mysql", "canyon_migrations/mysql", "canyon_macros/mysql"] +mysql = ["mysql_async", "mysql_common", "canyon_connection/mysql", "canyon_crud/mysql", "canyon_migrations/mysql", "canyon_macros/mysql"] migrations = ["canyon_migrations", "canyon_macros/migrations"] diff --git a/canyon_connection/Cargo.toml b/canyon_connection/Cargo.toml index e22d4b10..fac88ef5 100644 --- a/canyon_connection/Cargo.toml +++ b/canyon_connection/Cargo.toml @@ -16,6 +16,8 @@ tokio-util = { workspace = true } tokio-postgres = { workspace = true, optional = true } tiberius = { workspace = true, optional = true } mysql_async = { workspace = true, optional = true } +mysql_common = { workspace = true, optional = true } + futures = { workspace = true } indexmap = { workspace = true } @@ -29,5 +31,6 @@ walkdir = { workspace = true } [features] postgres = ["tokio-postgres"] mssql = ["tiberius", "async-std"] -mysql = ["mysql_async"] +mysql = ["mysql_async","mysql_common"] + diff --git a/canyon_connection/src/canyon_database_connector.rs b/canyon_connection/src/canyon_database_connector.rs index 764f7e6c..dbf54ece 100644 --- a/canyon_connection/src/canyon_database_connector.rs +++ b/canyon_connection/src/canyon_database_connector.rs @@ -186,8 +186,8 @@ impl DatabaseConnection { datasource.properties.port.unwrap_or_default(), datasource.properties.db_name ); - let mysql_connection = Conn::from_url(url).await?; + Ok(DatabaseConnection::MySQL(MysqlConnection { client: { mysql_connection }, })) diff --git a/canyon_crud/Cargo.toml b/canyon_crud/Cargo.toml index 13e7e8af..cd460534 100644 --- a/canyon_crud/Cargo.toml +++ b/canyon_crud/Cargo.toml @@ -13,6 +13,8 @@ description.workspace = true tokio-postgres = { workspace = true, optional = true } tiberius = { workspace = true, optional = true } mysql_async = { workspace = true, optional = true } +mysql_common = { workspace = true, optional = true } + chrono = { workspace = true } async-trait = { workspace = true } @@ -22,4 +24,4 @@ canyon_connection = { workspace = true } [features] postgres = ["tokio-postgres", "canyon_connection/postgres"] mssql = ["tiberius", "canyon_connection/mssql"] -mysql = ["mysql_async", "canyon_connection/mysql"] +mysql = ["mysql_async","mysql_common", "canyon_connection/mysql"] diff --git a/canyon_crud/src/bounds.rs b/canyon_crud/src/bounds.rs index d46bf863..f48c6101 100644 --- a/canyon_crud/src/bounds.rs +++ b/canyon_crud/src/bounds.rs @@ -3,14 +3,16 @@ use crate::{ mapper::RowMapper, }; +#[cfg(feature = "mysql")] +use canyon_connection::mysql_async::{self, prelude::ToValue, Value}; +#[cfg(feature = "mssql")] +use canyon_connection::tiberius::{self, ColumnData, IntoSql}; #[cfg(feature = "postgres")] use canyon_connection::tokio_postgres::{self, types::ToSql}; -#[cfg(feature = "mssql")] -use canyon_connection::tiberius::{self, ColumnData, IntoSql}; +use chrono::{DateTime, Datelike, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc}; -use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Utc}; -use std::any::Any; +use std::{any::Any, borrow::Cow}; /// Created for retrieve the field's name of a field of a struct, giving /// the Canyon's autogenerated enum with the variants that maps this @@ -100,16 +102,23 @@ impl Row for tiberius::Row { } } +#[cfg(feature = "mysql")] +impl Row for mysql_async::Row { + fn as_any(&self) -> &dyn Any { + self + } +} + /// Generic abstraction for hold a Column type that will be one of the Column /// types present in the dependent crates // #[derive(Copy, Clone)] pub struct Column<'a> { - name: &'a str, + name: Cow<'a, str>, type_: ColumnType, } impl<'a> Column<'a> { - pub fn name(&self) -> &'_ str { - self.name + pub fn name(&self) -> &str { + &self.name } pub fn column_type(&self) -> &ColumnType { &self.type_ @@ -137,6 +146,12 @@ impl Type for tiberius::ColumnType { self } } +#[cfg(feature = "mysql")] +impl Type for mysql_async::consts::ColumnType { + fn as_any(&self) -> &dyn Any { + self + } +} /// Wrapper over the dependencies Column's types pub enum ColumnType { @@ -144,6 +159,8 @@ pub enum ColumnType { Postgres(tokio_postgres::types::Type), #[cfg(feature = "mssql")] SqlServer(tiberius::ColumnType), + #[cfg(feature = "mysql")] + MySQL(mysql_async::consts::ColumnType), } pub trait RowOperations { @@ -155,6 +172,10 @@ pub trait RowOperations { fn get_mssql<'a, Output>(&'a self, col_name: &'a str) -> Output where Output: tiberius::FromSql<'a>; + #[cfg(feature = "mysql")] + fn get_mysql<'a, Output>(&'a self, col_name: &'a str) -> Output + where + Output: mysql_async::prelude::FromValue; #[cfg(feature = "postgres")] fn get_postgres_opt<'a, Output>(&'a self, col_name: &'a str) -> Option @@ -165,6 +186,11 @@ pub trait RowOperations { where Output: tiberius::FromSql<'a>; + #[cfg(feature = "mysql")] + fn get_mysql_opt<'a, Output>(&'a self, col_name: &'a str) -> Option + where + Output: mysql_async::prelude::FromValue; + fn columns(&self) -> Vec; } @@ -192,6 +218,15 @@ impl RowOperations for &dyn Row { panic!() // TODO into result and propagate } + #[cfg(feature = "mysql")] + fn get_mysql<'a, Output>(&'a self, col_name: &'a str) -> Output + where + Output: mysql_async::prelude::FromValue, + { + self.get_mysql_opt(col_name) + .expect("Failed to obtain a column in the MySql") + } + #[cfg(feature = "postgres")] fn get_postgres_opt<'a, Output>(&'a self, col_name: &'a str) -> Option where @@ -213,6 +248,16 @@ impl RowOperations for &dyn Row { }; panic!() // TODO into result and propagate } + #[cfg(feature = "mysql")] + fn get_mysql_opt<'a, Output>(&'a self, col_name: &'a str) -> Option + where + Output: mysql_async::prelude::FromValue, + { + if let Some(row) = self.as_any().downcast_ref::() { + return row.get::(col_name); + }; + panic!() // TODO into result and propagate + } fn columns(&self) -> Vec { let mut cols = vec![]; @@ -227,7 +272,7 @@ impl RowOperations for &dyn Row { .iter() .for_each(|c| { cols.push(Column { - name: c.name(), + name: Cow::from(c.name()), type_: ColumnType::Postgres(c.type_().to_owned()), }) }) @@ -243,12 +288,23 @@ impl RowOperations for &dyn Row { .iter() .for_each(|c| { cols.push(Column { - name: c.name(), + name: Cow::from(c.name()), type_: ColumnType::SqlServer(c.column_type()), }) }) }; } + #[cfg(feature = "mysql")] + { + if let Some(mysql_row) = self.as_any().downcast_ref::() { + mysql_row.columns_ref().iter().for_each(|c| { + cols.push(Column { + name: c.name_str(), + type_: ColumnType::MySQL(c.column_type()), + }) + }) + } + } cols } @@ -261,6 +317,8 @@ pub trait QueryParameter<'a>: std::fmt::Debug + Sync + Send { fn as_postgres_param(&self) -> &(dyn ToSql + Sync); #[cfg(feature = "mssql")] fn as_sqlserver_param(&self) -> ColumnData<'_>; + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue; } /// The implementation of the [`canyon_connection::tiberius`] [`IntoSql`] for the @@ -278,6 +336,8 @@ impl<'a> IntoSql<'a> for &'a dyn QueryParameter<'a> { } } +//TODO Pending to review and see if it is necessary to apply something similar to the previous implementation. + impl<'a> QueryParameter<'a> for bool { #[cfg(feature = "postgres")] fn as_postgres_param(&self) -> &(dyn ToSql + Sync) { @@ -287,6 +347,10 @@ impl<'a> QueryParameter<'a> for bool { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::Bit(Some(*self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn ToValue { + self + } } impl<'a> QueryParameter<'a> for i16 { #[cfg(feature = "postgres")] @@ -297,6 +361,10 @@ impl<'a> QueryParameter<'a> for i16 { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I16(Some(*self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for &i16 { #[cfg(feature = "postgres")] @@ -307,6 +375,10 @@ impl<'a> QueryParameter<'a> for &i16 { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I16(Some(**self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option { #[cfg(feature = "postgres")] @@ -317,6 +389,10 @@ impl<'a> QueryParameter<'a> for Option { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I16(*self) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option<&i16> { #[cfg(feature = "postgres")] @@ -327,6 +403,10 @@ impl<'a> QueryParameter<'a> for Option<&i16> { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I16(Some(*self.unwrap())) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for i32 { #[cfg(feature = "postgres")] @@ -337,6 +417,10 @@ impl<'a> QueryParameter<'a> for i32 { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I32(Some(*self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for &i32 { #[cfg(feature = "postgres")] @@ -347,6 +431,10 @@ impl<'a> QueryParameter<'a> for &i32 { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I32(Some(**self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option { #[cfg(feature = "postgres")] @@ -357,6 +445,10 @@ impl<'a> QueryParameter<'a> for Option { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I32(*self) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option<&i32> { #[cfg(feature = "postgres")] @@ -367,6 +459,10 @@ impl<'a> QueryParameter<'a> for Option<&i32> { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I32(Some(*self.unwrap())) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for f32 { #[cfg(feature = "postgres")] @@ -377,6 +473,10 @@ impl<'a> QueryParameter<'a> for f32 { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::F32(Some(*self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for &f32 { #[cfg(feature = "postgres")] @@ -387,6 +487,10 @@ impl<'a> QueryParameter<'a> for &f32 { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::F32(Some(**self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option { #[cfg(feature = "postgres")] @@ -397,6 +501,10 @@ impl<'a> QueryParameter<'a> for Option { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::F32(*self) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option<&f32> { #[cfg(feature = "postgres")] @@ -409,6 +517,10 @@ impl<'a> QueryParameter<'a> for Option<&f32> { *self.expect("Error on an f32 value on QueryParameter<'_>"), )) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for f64 { #[cfg(feature = "postgres")] @@ -419,6 +531,10 @@ impl<'a> QueryParameter<'a> for f64 { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::F64(Some(*self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for &f64 { #[cfg(feature = "postgres")] @@ -426,10 +542,13 @@ impl<'a> QueryParameter<'a> for &f64 { self } #[cfg(feature = "mssql")] - #[cfg(feature = "mssql")] fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::F64(Some(**self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option { #[cfg(feature = "postgres")] @@ -440,6 +559,10 @@ impl<'a> QueryParameter<'a> for Option { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::F64(*self) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option<&f64> { #[cfg(feature = "postgres")] @@ -452,6 +575,10 @@ impl<'a> QueryParameter<'a> for Option<&f64> { *self.expect("Error on an f64 value on QueryParameter<'_>"), )) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for i64 { #[cfg(feature = "postgres")] @@ -462,6 +589,10 @@ impl<'a> QueryParameter<'a> for i64 { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I64(Some(*self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for &i64 { #[cfg(feature = "postgres")] @@ -472,6 +603,10 @@ impl<'a> QueryParameter<'a> for &i64 { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I64(Some(**self)) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option { #[cfg(feature = "postgres")] @@ -482,6 +617,10 @@ impl<'a> QueryParameter<'a> for Option { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I64(*self) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option<&i64> { #[cfg(feature = "postgres")] @@ -492,6 +631,10 @@ impl<'a> QueryParameter<'a> for Option<&i64> { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::I64(Some(*self.unwrap())) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for String { #[cfg(feature = "postgres")] @@ -502,6 +645,10 @@ impl<'a> QueryParameter<'a> for String { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::String(Some(std::borrow::Cow::Owned(self.to_owned()))) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for &String { #[cfg(feature = "postgres")] @@ -512,6 +659,10 @@ impl<'a> QueryParameter<'a> for &String { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::String(Some(std::borrow::Cow::Borrowed(self))) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option { #[cfg(feature = "postgres")] @@ -525,6 +676,10 @@ impl<'a> QueryParameter<'a> for Option { None => ColumnData::String(None), } } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option<&String> { #[cfg(feature = "postgres")] @@ -538,6 +693,10 @@ impl<'a> QueryParameter<'a> for Option<&String> { None => ColumnData::String(None), } } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for &'_ str { #[cfg(feature = "postgres")] @@ -548,6 +707,10 @@ impl<'a> QueryParameter<'a> for &'_ str { fn as_sqlserver_param(&self) -> ColumnData<'_> { ColumnData::String(Some(std::borrow::Cow::Borrowed(*self))) } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option<&'_ str> { #[cfg(feature = "postgres")] @@ -561,6 +724,10 @@ impl<'a> QueryParameter<'a> for Option<&'_ str> { None => ColumnData::String(None), } } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for NaiveDate { #[cfg(feature = "postgres")] @@ -571,6 +738,10 @@ impl<'a> QueryParameter<'a> for NaiveDate { fn as_sqlserver_param(&self) -> ColumnData<'_> { self.into_sql() } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option { #[cfg(feature = "postgres")] @@ -581,6 +752,10 @@ impl<'a> QueryParameter<'a> for Option { fn as_sqlserver_param(&self) -> ColumnData<'_> { self.into_sql() } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for NaiveTime { #[cfg(feature = "postgres")] @@ -591,6 +766,10 @@ impl<'a> QueryParameter<'a> for NaiveTime { fn as_sqlserver_param(&self) -> ColumnData<'_> { self.into_sql() } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option { #[cfg(feature = "postgres")] @@ -601,6 +780,10 @@ impl<'a> QueryParameter<'a> for Option { fn as_sqlserver_param(&self) -> ColumnData<'_> { self.into_sql() } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for NaiveDateTime { #[cfg(feature = "postgres")] @@ -611,6 +794,10 @@ impl<'a> QueryParameter<'a> for NaiveDateTime { fn as_sqlserver_param(&self) -> ColumnData<'_> { self.into_sql() } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } impl<'a> QueryParameter<'a> for Option { #[cfg(feature = "postgres")] @@ -621,7 +808,13 @@ impl<'a> QueryParameter<'a> for Option { fn as_sqlserver_param(&self) -> ColumnData<'_> { self.into_sql() } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + self + } } + +//TODO pending impl<'a> QueryParameter<'a> for DateTime { #[cfg(feature = "postgres")] fn as_postgres_param(&self) -> &(dyn ToSql + Sync) { @@ -631,7 +824,12 @@ impl<'a> QueryParameter<'a> for DateTime { fn as_sqlserver_param(&self) -> ColumnData<'_> { self.into_sql() } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + todo!() + } } + impl<'a> QueryParameter<'a> for Option> { #[cfg(feature = "postgres")] fn as_postgres_param(&self) -> &(dyn ToSql + Sync) { @@ -641,7 +839,12 @@ impl<'a> QueryParameter<'a> for Option> { fn as_sqlserver_param(&self) -> ColumnData<'_> { self.into_sql() } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + todo!() + } } + impl<'a> QueryParameter<'a> for DateTime { #[cfg(feature = "postgres")] fn as_postgres_param(&self) -> &(dyn ToSql + Sync) { @@ -651,7 +854,12 @@ impl<'a> QueryParameter<'a> for DateTime { fn as_sqlserver_param(&self) -> ColumnData<'_> { self.into_sql() } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + todo!() + } } + impl<'a> QueryParameter<'a> for Option> { #[cfg(feature = "postgres")] fn as_postgres_param(&self) -> &(dyn ToSql + Sync) { @@ -661,4 +869,8 @@ impl<'a> QueryParameter<'a> for Option> { fn as_sqlserver_param(&self) -> ColumnData<'_> { self.into_sql() } + #[cfg(feature = "mysql")] + fn as_mysql_param(&self) -> &dyn mysql_async::prelude::ToValue { + todo!() + } } diff --git a/canyon_migrations/Cargo.toml b/canyon_migrations/Cargo.toml index 39211c00..ec9a31db 100644 --- a/canyon_migrations/Cargo.toml +++ b/canyon_migrations/Cargo.toml @@ -18,6 +18,8 @@ tokio = { workspace = true } tokio-postgres = { workspace = true, optional = true } tiberius = { workspace = true, optional = true } mysql_async = { workspace = true, optional = true } +mysql_common = { workspace = true, optional = true } + async-trait = { workspace = true } @@ -31,5 +33,5 @@ syn = { version = "1.0.86", features = ["full", "parsing"] } # TODO Pending to r [features] postgres = ["tokio-postgres", "canyon_connection/postgres", "canyon_crud/postgres"] mssql = ["tiberius", "canyon_connection/mssql", "canyon_crud/mssql"] -mysql = ["mysql_async", "canyon_connection/mysql", "canyon_crud/mysql"] +mysql = ["mysql_async","mysql_common", "canyon_connection/mysql", "canyon_crud/mysql"] From e067220f10360e1e74dc4f19d1a365896d311c25 Mon Sep 17 00:00:00 2001 From: onsystem Date: Sun, 30 Jul 2023 14:40:03 +0200 Subject: [PATCH 04/27] mysql-support canyon macros, pending trait implement FromValue in &str and chrono:Date --- .../src/canyon_database_connector.rs | 8 ++-- canyon_crud/src/bounds.rs | 5 ++- canyon_crud/src/crud.rs | 39 ++++++++++++++++++- canyon_crud/src/mapper.rs | 4 ++ canyon_crud/src/rows.rs | 17 ++++++++ canyon_macros/src/lib.rs | 18 +++++++++ .../src/migrations/information_schema.rs | 2 + src/lib.rs | 2 + 8 files changed, 88 insertions(+), 7 deletions(-) diff --git a/canyon_connection/src/canyon_database_connector.rs b/canyon_connection/src/canyon_database_connector.rs index dbf54ece..6b2b783d 100644 --- a/canyon_connection/src/canyon_database_connector.rs +++ b/canyon_connection/src/canyon_database_connector.rs @@ -3,7 +3,7 @@ use serde::Deserialize; #[cfg(feature = "mssql")] use async_std::net::TcpStream; #[cfg(feature = "mysql")] -use mysql_async::Conn; +use mysql_async::Pool; #[cfg(feature = "mssql")] use tiberius::{AuthMethod, Config}; #[cfg(feature = "postgres")] @@ -41,7 +41,7 @@ pub struct SqlServerConnection { /// A connection with a `Mysql` database #[cfg(feature = "mysql")] pub struct MysqlConnection { - pub client: Conn, //TODO this is Connection with server but it could be interesting to use Pool + pub client: Pool, //TODO this is Connection with server but it could be interesting to use Pool } /// The Canyon database connection handler. When the client's program @@ -186,7 +186,7 @@ impl DatabaseConnection { datasource.properties.port.unwrap_or_default(), datasource.properties.db_name ); - let mysql_connection = Conn::from_url(url).await?; + let mysql_connection = Pool::from_url(url)?; Ok(DatabaseConnection::MySQL(MysqlConnection { client: { mysql_connection }, @@ -214,7 +214,7 @@ impl DatabaseConnection { } #[cfg(feature = "mysql")] - pub fn mysql_connection(&mut self) -> &mut MysqlConnection { + pub fn mysql_connection(&self) -> &MysqlConnection { match self { DatabaseConnection::MySQL(conn) => conn, #[cfg(all(feature = "postgres", feature = "mssql", feature = "mysql"))] diff --git a/canyon_crud/src/bounds.rs b/canyon_crud/src/bounds.rs index f48c6101..a75b3cac 100644 --- a/canyon_crud/src/bounds.rs +++ b/canyon_crud/src/bounds.rs @@ -4,13 +4,14 @@ use crate::{ }; #[cfg(feature = "mysql")] -use canyon_connection::mysql_async::{self, prelude::ToValue, Value}; +use canyon_connection::mysql_async::{self, prelude::ToValue}; + #[cfg(feature = "mssql")] use canyon_connection::tiberius::{self, ColumnData, IntoSql}; #[cfg(feature = "postgres")] use canyon_connection::tokio_postgres::{self, types::ToSql}; -use chrono::{DateTime, Datelike, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc}; +use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Utc}; use std::{any::Any, borrow::Cow}; diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 8185a0b2..77fbf3c1 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -54,7 +54,7 @@ pub trait Transaction { } #[cfg(feature = "mssql")] DatabaseConnection::MySQL(_) => { - todo!("Pending to implement") + mysql_query_launcher::launch(database_conn, stmt.to_string(), params.as_ref()).await } } } @@ -221,3 +221,40 @@ mod sqlserver_query_launcher { )) } } + +#[cfg(feature = "mysql")] +mod mysql_query_launcher { + use canyon_connection::canyon_database_connector::DatabaseConnection; + use mysql_async::from_value; + use mysql_async::prelude::Query; + use mysql_async::QueryWithParams; + use mysql_async::Value; + + use crate::bounds::QueryParameter; + use crate::rows::CanyonRows; + + pub async fn launch<'a, T>( + db_conn: &DatabaseConnection, + stmt: String, + params: &'a [&'_ dyn QueryParameter<'_>], + ) -> Result, Box<(dyn std::error::Error + Send + Sync + 'static)>> { + let mysql_connection = db_conn.mysql_connection().client.get_conn().await?; + + let query_string = stmt.clone(); + + let mut params_query: Vec = Vec::new(); + + for param in params { + params_query.push(from_value(param.as_mysql_param().to_value())); + } + + let query_with_params = QueryWithParams { + query: query_string, + params: params_query, + }; + + //let result = mysql_connection.get_conn().await?.exec(query_string, params_query); + let result: Vec = query_with_params.fetch(mysql_connection).await?; + Ok(CanyonRows::MySQL(result)) + } +} diff --git a/canyon_crud/src/mapper.rs b/canyon_crud/src/mapper.rs index 66cb91d2..2775f0fe 100644 --- a/canyon_crud/src/mapper.rs +++ b/canyon_crud/src/mapper.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "mysql")] +use canyon_connection::mysql_async; #[cfg(feature = "mssql")] use canyon_connection::tiberius; #[cfg(feature = "postgres")] @@ -13,4 +15,6 @@ pub trait RowMapper>: Sized { fn deserialize_postgresql(row: &tokio_postgres::Row) -> T; #[cfg(feature = "mssql")] fn deserialize_sqlserver(row: &tiberius::Row) -> T; + #[cfg(feature = "mysql_async")] + fn deserialize_mysql(row: &mysql_async::Row) -> T; } diff --git a/canyon_crud/src/rows.rs b/canyon_crud/src/rows.rs index d8d35070..517592a6 100644 --- a/canyon_crud/src/rows.rs +++ b/canyon_crud/src/rows.rs @@ -13,6 +13,9 @@ pub enum CanyonRows { Postgres(Vec), #[cfg(feature = "mssql")] Tiberius(Vec), + #[cfg(feature = "mysql")] + MySQL(Vec), + UnusableTypeMarker(PhantomData), } @@ -33,6 +36,14 @@ impl CanyonRows { } } + #[cfg(feature = "mysql")] + pub fn get_mysql_rows(&self) -> &Vec { + match self { + Self::MySQL(v) => v, + _ => panic!("This branch will never ever should be reachable"), + } + } + /// Consumes `self` and returns the wrapped [`std::vec::Vec`] with the instances of T pub fn into_results>(self) -> Vec where @@ -43,6 +54,8 @@ impl CanyonRows { Self::Postgres(v) => v.iter().map(|row| Z::deserialize_postgresql(row)).collect(), #[cfg(feature = "mssql")] Self::Tiberius(v) => v.iter().map(|row| Z::deserialize_sqlserver(row)).collect(), + #[cfg(feature = "mysql")] + Self::MySQL(v) => v.iter().map(|row| Z::deserialize_mysql(row)).collect(), _ => panic!("This branch will never ever should be reachable"), } } @@ -54,6 +67,8 @@ impl CanyonRows { Self::Postgres(v) => v.len(), #[cfg(feature = "mssql")] Self::Tiberius(v) => v.len(), + #[cfg(feature = "mysql")] + Self::MySQL(v) => v.len(), _ => panic!("This branch will never ever should be reachable"), } } @@ -65,6 +80,8 @@ impl CanyonRows { Self::Postgres(v) => v.is_empty(), #[cfg(feature = "mssql")] Self::Tiberius(v) => v.is_empty(), + #[cfg(feature = "mysql")] + Self::MySQL(v) => v.is_empty(), _ => panic!("This branch will never ever should be reachable"), } } diff --git a/canyon_macros/src/lib.rs b/canyon_macros/src/lib.rs index 160f6ece..86198687 100755 --- a/canyon_macros/src/lib.rs +++ b/canyon_macros/src/lib.rs @@ -530,12 +530,15 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac } } }); + //TODO + let init_field_values_mysql = init_field_values_sqlserver.clone(); // The type of the Struct let ty = ast.ident; let postgres_enabled = cfg!(feature = "postgres"); let mssql_enabled = cfg!(feature = "mssql"); + let mysql_enabled = cfg!(feature = "mysql"); let tokens = if postgres_enabled && mssql_enabled { quote! { @@ -550,6 +553,11 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac #(#init_field_values_sqlserver),* } } + fn deserialize_mysql(row:&canyon_sql::db_clients::mysql_async::Row) -> #ty { + Self { + #(#init_field_values_mysql),* + } + } } } } else if postgres_enabled { @@ -572,6 +580,16 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac } } } + } else if mysql_enabled { + quote! { + impl canyon_sql::crud::RowMapper for #ty { + fn deserialize_mysql(row:&canyon_sql::db_clients::mysql_async::Row) -> #ty { + Self { + #(#init_field_values_mysql),* + } + } + } + } } else { quote! { panic!( diff --git a/canyon_migrations/src/migrations/information_schema.rs b/canyon_migrations/src/migrations/information_schema.rs index 74709619..9e165eee 100644 --- a/canyon_migrations/src/migrations/information_schema.rs +++ b/canyon_migrations/src/migrations/information_schema.rs @@ -67,6 +67,8 @@ impl ColumnMetadataTypeValue { } _ => Self::NoneValue, }, + #[cfg(feature = "mysql")] + ColumnType::MySQL(_) => todo!(), } } } diff --git a/src/lib.rs b/src/lib.rs index d89f79b2..18e334a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,8 @@ pub mod query { /// Reexport the available database clients within Canyon pub mod db_clients { + #[cfg(feature = "mysql")] + pub use canyon_connection::mysql_async; #[cfg(feature = "mssql")] pub use canyon_connection::tiberius; #[cfg(feature = "postgres")] From e53d7c63378a735b27873929b8cba3e48d4e1540 Mon Sep 17 00:00:00 2001 From: onsystem Date: Mon, 7 Aug 2023 23:14:22 +0200 Subject: [PATCH 05/27] mysql-support count table implemented --- canyon_crud/src/crud.rs | 1 - canyon_crud/src/mapper.rs | 2 +- canyon_macros/src/lib.rs | 18 ++++-- canyon_macros/src/query_operations/select.rs | 15 ++++- src/lib.rs | 3 + tests/canyon.toml | 2 +- tests/crud/select_operations.rs | 58 ++++++++++++++++++-- 7 files changed, 82 insertions(+), 17 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 77fbf3c1..d0c35816 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -253,7 +253,6 @@ mod mysql_query_launcher { params: params_query, }; - //let result = mysql_connection.get_conn().await?.exec(query_string, params_query); let result: Vec = query_with_params.fetch(mysql_connection).await?; Ok(CanyonRows::MySQL(result)) } diff --git a/canyon_crud/src/mapper.rs b/canyon_crud/src/mapper.rs index 2775f0fe..252df1ce 100644 --- a/canyon_crud/src/mapper.rs +++ b/canyon_crud/src/mapper.rs @@ -15,6 +15,6 @@ pub trait RowMapper>: Sized { fn deserialize_postgresql(row: &tokio_postgres::Row) -> T; #[cfg(feature = "mssql")] fn deserialize_sqlserver(row: &tiberius::Row) -> T; - #[cfg(feature = "mysql_async")] + #[cfg(feature = "mysql")] fn deserialize_mysql(row: &mysql_async::Row) -> T; } diff --git a/canyon_macros/src/lib.rs b/canyon_macros/src/lib.rs index 86198687..56ff449a 100755 --- a/canyon_macros/src/lib.rs +++ b/canyon_macros/src/lib.rs @@ -2,6 +2,7 @@ extern crate proc_macro; mod canyon_entity_macro; #[cfg(feature = "migrations")] +use canyon_macro::main_with_queries; mod canyon_macro; mod query_operations; mod utils; @@ -13,8 +14,6 @@ use quote::{quote, ToTokens}; use syn::{DeriveInput, Fields, Type, Visibility}; #[cfg(feature = "migrations")] -use canyon_macro::main_with_queries; - use query_operations::{ delete::{generate_delete_query_tokens, generate_delete_tokens}, insert::{generate_insert_tokens, generate_multiple_insert_tokens}, @@ -530,8 +529,15 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac } } }); + //TODO - let init_field_values_mysql = init_field_values_sqlserver.clone(); + let init_field_values_mysql = fields.iter().map(|(_vis, ident, _ty)| { + let ident_name = ident.to_string(); + quote! { + #ident: row.get(#ident_name) + .expect(format!("Failed to retrieve the {} field", #ident_name).as_ref()) + } + }); // The type of the Struct let ty = ast.ident; @@ -540,7 +546,7 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac let mssql_enabled = cfg!(feature = "mssql"); let mysql_enabled = cfg!(feature = "mysql"); - let tokens = if postgres_enabled && mssql_enabled { + let tokens = if postgres_enabled && mssql_enabled && mysql_enabled { quote! { impl canyon_sql::crud::RowMapper for #ty { fn deserialize_postgresql(row: &canyon_sql::db_clients::tokio_postgres::Row) -> #ty { @@ -553,7 +559,7 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac #(#init_field_values_sqlserver),* } } - fn deserialize_mysql(row:&canyon_sql::db_clients::mysql_async::Row) -> #ty { + fn deserialize_mysql(row: &canyon_sql::db_clients::mysql_async::Row) -> #ty { Self { #(#init_field_values_mysql),* } @@ -583,7 +589,7 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac } else if mysql_enabled { quote! { impl canyon_sql::crud::RowMapper for #ty { - fn deserialize_mysql(row:&canyon_sql::db_clients::mysql_async::Row) -> #ty { + fn deserialize_mysql(row: &canyon_sql::db_clients::mysql_async::Row) -> #ty { Self { #(#init_field_values_mysql),* } diff --git a/canyon_macros/src/query_operations/select.rs b/canyon_macros/src/query_operations/select.rs index 5a5a4e15..3556d42c 100644 --- a/canyon_macros/src/query_operations/select.rs +++ b/canyon_macros/src/query_operations/select.rs @@ -148,12 +148,13 @@ pub fn generate_count_tokens( ) -> TokenStream { let ty = macro_data.ty; let ty_str = &ty.to_string(); - let stmt = format!("SELECT COUNT (*) FROM {table_schema_data}"); + let stmt = format!("SELECT COUNT(*) FROM {table_schema_data}"); let postgres_enabled = cfg!(feature = "postgres"); let mssql_enabled = cfg!(feature = "mssql"); + let mysql_enabled = cfg!(feature = "mysql"); - let result_handling = if postgres_enabled && mssql_enabled { + let result_handling = if postgres_enabled && mssql_enabled && mysql_enabled { quote! { canyon_sql::crud::CanyonRows::Postgres(mut v) => Ok( v.remove(0).get::<&str, i64>("count") @@ -164,6 +165,9 @@ pub fn generate_count_tokens( .map(|c| c as i64) .ok_or(format!("Failure in the COUNT query for MSSQL for: {}", #ty_str).into()) .into(), + canyon_sql::crud::CanyonRows::MySQL(mut v) => v.remove(0) + .get::(0) + .ok_or(format!("Failure in the COUNT query for MYSQL for: {}", #ty_str).into()), _ => panic!() // TODO remove when the generics will be refactored } } else if postgres_enabled { @@ -183,6 +187,13 @@ pub fn generate_count_tokens( .into(), _ => panic!() // TODO remove when the generics will be refactored } + } else if mysql_enabled { + quote! { + canyon_sql::crud::CanyonRows::MySQL(mut v) => v.remove(0) + .get::(0) + .ok_or(format!("Failure result empty in the COUNT query for MYSQL for: {}", #ty_str).into()), + _ => panic!() + } } else { quote! { panic!( diff --git a/src/lib.rs b/src/lib.rs index 18e334a4..307d8b08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,9 @@ pub mod connection { #[cfg(feature = "mssql")] pub use canyon_connection::canyon_database_connector::DatabaseConnection::SqlServer; + + #[cfg(feature = "mysql")] + pub use canyon_connection::canyon_database_connector::DatabaseConnection::MySQL; } /// Crud module serves to reexport the public elements of the `canyon_crud` crate, diff --git a/tests/canyon.toml b/tests/canyon.toml index e31be9a2..73c0b023 100644 --- a/tests/canyon.toml +++ b/tests/canyon.toml @@ -32,5 +32,5 @@ mysql = { basic = { username = 'root', password = 'root' } } [canyon_sql.datasources.properties] host = 'localhost' -port = 1434 +port = 3307 db_name = 'public' \ No newline at end of file diff --git a/tests/crud/select_operations.rs b/tests/crud/select_operations.rs index 9f9a6f5c..51dc8259 100644 --- a/tests/crud/select_operations.rs +++ b/tests/crud/select_operations.rs @@ -1,5 +1,8 @@ #![allow(clippy::nonminimal_bool)] +#[cfg(feature = "mssql")] +use crate::constants::MYSQL_DS; + #[cfg(feature = "mssql")] use crate::constants::SQL_SERVER_DS; ///! Integration tests for the CRUD operations available in `Canyon` that @@ -42,7 +45,7 @@ fn test_crud_find_all_unchecked() { /// and using the specified datasource #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_find_all_datasource() { +fn test_crud_find_all_datasource_mssql() { let find_all_result: Result, Box> = League::find_all_datasource(SQL_SERVER_DS).await; // Connection doesn't return an error @@ -50,6 +53,16 @@ fn test_crud_find_all_datasource() { assert!(!find_all_result.unwrap().is_empty()); } +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_find_all_datasource_mysql() { + let find_all_result: Result, Box> = + League::find_all_datasource(MYSQL_DS).await; + // Connection doesn't return an error + assert!(!find_all_result.is_err()); + assert!(!find_all_result.unwrap().is_empty()); +} + /// Same as the `find_all_datasource()`, but with the unchecked variant and the specified dataosource, /// returning directly `Vec` and not `Result, Err>` #[cfg(feature = "mssql")] @@ -85,11 +98,10 @@ fn test_crud_find_by_pk() { /// Tests the behaviour of a SELECT * FROM {table_name} WHERE = , where the pk is /// defined with the #[primary_key] attribute over some field of the type. /// -/// Uses the *specified datasource* in the second parameter of the function call. -#[cfg(feature = "postgres")] +/// Uses the *specified datasource mssql* in the second parameter of the function call. #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_find_by_pk_datasource() { +fn test_crud_find_by_pk_datasource_mssql() { let find_by_pk_result: Result, Box> = League::find_by_pk_datasource(&27, SQL_SERVER_DS).await; assert!(find_by_pk_result.as_ref().unwrap().is_some()); @@ -106,6 +118,29 @@ fn test_crud_find_by_pk_datasource() { ); } +/// Tests the behaviour of a SELECT * FROM {table_name} WHERE = , where the pk is +/// defined with the #[primary_key] attribute over some field of the type. +/// +/// Uses the *specified datasource mysql* in the second parameter of the function call. +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_find_by_pk_datasource_mysql() { + let find_by_pk_result: Result, Box> = + League::find_by_pk_datasource(&27, MYSQL_DS).await; + assert!(find_by_pk_result.as_ref().unwrap().is_some()); + + let some_league = find_by_pk_result.unwrap().unwrap(); + assert_eq!(some_league.id, 27); + assert_eq!(some_league.ext_id, 107898214974993351_i64); + assert_eq!(some_league.slug, "college_championship"); + assert_eq!(some_league.name, "College Championship"); + assert_eq!(some_league.region, "NORTH AMERICA"); + assert_eq!( + some_league.image_url, + "http://static.lolesports.com/leagues/1646396098648_CollegeChampionshiplogo.png" + ); +} + /// Counts how many rows contains an entity on the target database. #[cfg(feature = "postgres")] #[canyon_sql::macros::canyon_tokio_test] @@ -117,10 +152,10 @@ fn test_crud_count_operation() { } /// Counts how many rows contains an entity on the target database using -/// the specified datasource +/// the specified datasource mssql #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_count_datasource_operation() { +fn test_crud_count_datasource_operation_mssql() { assert_eq!( League::find_all_datasource(SQL_SERVER_DS) .await @@ -129,3 +164,14 @@ fn test_crud_count_datasource_operation() { League::count_datasource(SQL_SERVER_DS).await.unwrap() ); } + +/// Counts how many rows contains an entity on the target database using +/// the specified datasource mysql +#[cfg(feature = "mssql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_count_datasource_operation_mysql() { + assert_eq!( + League::find_all_datasource(MYSQL_DS).await.unwrap().len() as i64, + League::count_datasource(MYSQL_DS).await.unwrap() + ); +} From bf21ca769e28cab2c22d44e1eedae02ae44d5ae6 Mon Sep 17 00:00:00 2001 From: onsystem Date: Fri, 11 Aug 2023 16:39:06 +0200 Subject: [PATCH 06/27] mysql-support - pending implement select test --- canyon_crud/src/crud.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index d0c35816..f35c15c2 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -239,8 +239,8 @@ mod mysql_query_launcher { params: &'a [&'_ dyn QueryParameter<'_>], ) -> Result, Box<(dyn std::error::Error + Send + Sync + 'static)>> { let mysql_connection = db_conn.mysql_connection().client.get_conn().await?; - - let query_string = stmt.clone(); + //TODO implement expresion pattern to replace + let query_string = stmt.to_owned().replace('$', "?"); let mut params_query: Vec = Vec::new(); From 904e554e121967ff6cc4b45b6076f43cd5e16aec Mon Sep 17 00:00:00 2001 From: OnSystem Date: Sat, 12 Aug 2023 13:04:38 +0200 Subject: [PATCH 07/27] mysql-support craete reorder array params to use with mysql params --- Cargo.toml | 4 +- canyon_crud/Cargo.toml | 3 +- canyon_crud/src/crud.rs | 53 +++++++++++++++++++++---- canyon_macros/src/lib.rs | 3 +- canyon_macros/src/utils/macro_tokens.rs | 2 +- tests/crud/select_operations.rs | 4 +- tests/crud/update_operations.rs | 47 +++++++++++++++++++++- 7 files changed, 100 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2ed3e31c..c5063ad6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,12 +58,14 @@ lazy_static = "1.4.0" toml = "0.7.3" async-trait = "0.1.68" walkdir = "2.3.3" -regex = "1.5" +regex = "1.9.3" partialdebug = "0.2.0" quote = "1.0.9" proc-macro2 = "1.0.27" + + [workspace.package] version = "0.4.2" edition = "2021" diff --git a/canyon_crud/Cargo.toml b/canyon_crud/Cargo.toml index cd460534..dfdd3ddb 100644 --- a/canyon_crud/Cargo.toml +++ b/canyon_crud/Cargo.toml @@ -15,12 +15,13 @@ tiberius = { workspace = true, optional = true } mysql_async = { workspace = true, optional = true } mysql_common = { workspace = true, optional = true } - chrono = { workspace = true } async-trait = { workspace = true } canyon_connection = { workspace = true } +regex = { workspace = true } + [features] postgres = ["tokio-postgres", "canyon_connection/postgres"] mssql = ["tiberius", "canyon_connection/mssql"] diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index f35c15c2..ccdc3ff7 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -2,7 +2,9 @@ use std::fmt::Display; use async_trait::async_trait; use canyon_connection::canyon_database_connector::DatabaseConnection; +use canyon_connection::lazy_static::lazy_static; use canyon_connection::{get_database_connection, CACHED_DATABASE_CONN}; +use regex::Regex; use crate::bounds::QueryParameter; use crate::mapper::RowMapper; @@ -11,6 +13,10 @@ use crate::query_elements::query_builder::{ }; use crate::rows::CanyonRows; +lazy_static! { + static ref REGEX_DETECT_PARAMS: Regex = + Regex::new(r"\$([\d])+").expect("Error building regex pattern to detect params"); +} /// This traits defines and implements a query against a database given /// an statement `stmt` and the params to pass the to the client. /// @@ -54,7 +60,7 @@ pub trait Transaction { } #[cfg(feature = "mssql")] DatabaseConnection::MySQL(_) => { - mysql_query_launcher::launch(database_conn, stmt.to_string(), params.as_ref()).await + mysql_query_launcher::launch(database_conn, stmt.to_string(), params).await } } } @@ -233,27 +239,58 @@ mod mysql_query_launcher { use crate::bounds::QueryParameter; use crate::rows::CanyonRows; - pub async fn launch<'a, T>( + use super::REGEX_DETECT_PARAMS; + + pub async fn launch<'a, T, Z>( db_conn: &DatabaseConnection, stmt: String, - params: &'a [&'_ dyn QueryParameter<'_>], - ) -> Result, Box<(dyn std::error::Error + Send + Sync + 'static)>> { + params: Z, + ) -> Result, Box<(dyn std::error::Error + Send + Sync + 'static)>> + where + Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, + { let mysql_connection = db_conn.mysql_connection().client.get_conn().await?; - //TODO implement expresion pattern to replace - let query_string = stmt.to_owned().replace('$', "?"); + + let query_string = REGEX_DETECT_PARAMS.replace_all(&stmt, "?"); let mut params_query: Vec = Vec::new(); - for param in params { + for param in reorder_params_to_mysql(&stmt, params) { params_query.push(from_value(param.as_mysql_param().to_value())); } let query_with_params = QueryWithParams { - query: query_string, + query: query_string.into_owned(), params: params_query, }; let result: Vec = query_with_params.fetch(mysql_connection).await?; Ok(CanyonRows::MySQL(result)) } + + pub fn reorder_params_to_mysql<'a, 'b, Z>( + stmt: &'b str, + params: Z, + ) -> Vec<&'a dyn QueryParameter<'a>> + where + Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, + { + let mut ordered_params = vec![]; + + for positional_param in REGEX_DETECT_PARAMS.find_iter(stmt) { + let pp = positional_param.as_str(); + let pp_index = pp[1..] + .parse::() + .expect("error parse mapped parameter to usized.") + - 1; + + let element = *params + .as_ref() + .get(pp_index) + .expect("error obtaining the element of the mapping against parameters."); + ordered_params.push(element); + } + + ordered_params + } } diff --git a/canyon_macros/src/lib.rs b/canyon_macros/src/lib.rs index 56ff449a..3eae3d99 100755 --- a/canyon_macros/src/lib.rs +++ b/canyon_macros/src/lib.rs @@ -3,6 +3,7 @@ extern crate proc_macro; mod canyon_entity_macro; #[cfg(feature = "migrations")] use canyon_macro::main_with_queries; + mod canyon_macro; mod query_operations; mod utils; @@ -13,7 +14,6 @@ use proc_macro2::{Ident, TokenStream}; use quote::{quote, ToTokens}; use syn::{DeriveInput, Fields, Type, Visibility}; -#[cfg(feature = "migrations")] use query_operations::{ delete::{generate_delete_query_tokens, generate_delete_tokens}, insert::{generate_insert_tokens, generate_multiple_insert_tokens}, @@ -530,7 +530,6 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac } }); - //TODO let init_field_values_mysql = fields.iter().map(|(_vis, ident, _ty)| { let ident_name = ident.to_string(); quote! { diff --git a/canyon_macros/src/utils/macro_tokens.rs b/canyon_macros/src/utils/macro_tokens.rs index 29de0467..eb2b4684 100644 --- a/canyon_macros/src/utils/macro_tokens.rs +++ b/canyon_macros/src/utils/macro_tokens.rs @@ -92,7 +92,7 @@ impl<'a> MacroTokens<'a> { true } }) - .map(|c| format!("\"{}\"", c.ident.as_ref().unwrap())) + .map(|c| format!("{}", c.ident.as_ref().unwrap())) .collect::>() } diff --git a/tests/crud/select_operations.rs b/tests/crud/select_operations.rs index 51dc8259..76d263f2 100644 --- a/tests/crud/select_operations.rs +++ b/tests/crud/select_operations.rs @@ -1,6 +1,6 @@ #![allow(clippy::nonminimal_bool)] -#[cfg(feature = "mssql")] +#[cfg(feature = "mysql")] use crate::constants::MYSQL_DS; #[cfg(feature = "mssql")] @@ -167,7 +167,7 @@ fn test_crud_count_datasource_operation_mssql() { /// Counts how many rows contains an entity on the target database using /// the specified datasource mysql -#[cfg(feature = "mssql")] +#[cfg(feature = "mysql")] #[canyon_sql::macros::canyon_tokio_test] fn test_crud_count_datasource_operation_mysql() { assert_eq!( diff --git a/tests/crud/update_operations.rs b/tests/crud/update_operations.rs index e4085560..6dd4c223 100644 --- a/tests/crud/update_operations.rs +++ b/tests/crud/update_operations.rs @@ -6,6 +6,9 @@ use canyon_sql::crud::CrudOperations; use crate::constants::SQL_SERVER_DS; use crate::tests_models::league::*; +#[cfg(feature = "mysql")] +use crate::constants::MYSQL_DS; + /// Update operation is a *CRUD* method defined for some entity `T`, that works by appliying /// some change to a Rust's entity instance, and persisting them into the database. /// @@ -59,7 +62,7 @@ fn test_crud_update_method_operation() { /// Same as the above test, but with the specified datasource. #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_update_datasource_method_operation() { +fn test_crud_update_datasource_mssql_method_operation() { // We first retrieve some entity from the database. Note that we must make // the retrieved instance mutable of clone it to a new mutable resource let mut updt_candidate: League = League::find_by_pk_datasource(&1, SQL_SERVER_DS) @@ -96,3 +99,45 @@ fn test_crud_update_datasource_method_operation() { .await .expect("Failed to restablish the initial value update operation"); } + +/// Same as the above test, but with the specified datasource. +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_update_datasource_mysql_method_operation() { + // We first retrieve some entity from the database. Note that we must make + // the retrieved instance mutable of clone it to a new mutable resource + + let mut updt_candidate: League = League::find_by_pk_datasource(&1, MYSQL_DS) + .await + .expect("[1] - Failed the query to the database") + .expect("[1] - No entity found for the primary key value passed in"); + + // The ext_id field value is extracted from the sql scripts under the + // docker/sql folder. We are retrieving the first entity inserted at the + // wake up time of the database, and now checking some of its properties. + assert_eq!(updt_candidate.ext_id, 100695891328981122_i64); + + // Modify the value, and perform the update + let updt_value: i64 = 59306442534_i64; + updt_candidate.ext_id = updt_value; + updt_candidate + .update_datasource(MYSQL_DS) + .await + .expect("Failed the update operation"); + + // Retrieve it again, and check if the value was really updated + let updt_entity: League = League::find_by_pk_datasource(&1, MYSQL_DS) + .await + .expect("[2] - Failed the query to the database") + .expect("[2] - No entity found for the primary key value passed in"); + + assert_eq!(updt_entity.ext_id, updt_value); + + // We rollback the changes to the initial value to don't broke other tests + // the next time that will run + updt_candidate.ext_id = 100695891328981122_i64; + updt_candidate + .update_datasource(MYSQL_DS) + .await + .expect("Failed to restablish the initial value update operation"); +} From f3376fc8d85b0b95720471d8c934c232229e59cf Mon Sep 17 00:00:00 2001 From: OnSystem Date: Mon, 21 Aug 2023 19:49:28 +0200 Subject: [PATCH 08/27] mysql-support resolve quotes in queries and innecesary loop in reorder map --- canyon_crud/src/crud.rs | 84 +++++++++++++------------ canyon_macros/src/utils/macro_tokens.rs | 2 +- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index ccdc3ff7..26709d32 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -16,6 +16,8 @@ use crate::rows::CanyonRows; lazy_static! { static ref REGEX_DETECT_PARAMS: Regex = Regex::new(r"\$([\d])+").expect("Error building regex pattern to detect params"); + static ref REGEX_DETECT_QUOTE: Regex = //Temporal solution escape quotes + Regex::new(r#"\"|\\"#).expect("Error building regex pattern to detect quotes"); } /// This traits defines and implements a query against a database given /// an statement `stmt` and the params to pass the to the client. @@ -60,7 +62,8 @@ pub trait Transaction { } #[cfg(feature = "mssql")] DatabaseConnection::MySQL(_) => { - mysql_query_launcher::launch(database_conn, stmt.to_string(), params).await + mysql_query_launcher::launch::(database_conn, stmt.to_string(), params.as_ref()) + .await } } } @@ -230,67 +233,70 @@ mod sqlserver_query_launcher { #[cfg(feature = "mysql")] mod mysql_query_launcher { + use canyon_connection::canyon_database_connector::DatabaseConnection; - use mysql_async::from_value; + use mysql_async::prelude::Query; use mysql_async::QueryWithParams; use mysql_async::Value; use crate::bounds::QueryParameter; + use crate::crud::REGEX_DETECT_QUOTE; use crate::rows::CanyonRows; + use super::reorder_params; use super::REGEX_DETECT_PARAMS; - pub async fn launch<'a, T, Z>( + pub async fn launch<'a, T>( db_conn: &DatabaseConnection, stmt: String, - params: Z, - ) -> Result, Box<(dyn std::error::Error + Send + Sync + 'static)>> - where - Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, - { + params: &'a [&'_ dyn QueryParameter<'_>], + ) -> Result, Box<(dyn std::error::Error + Send + Sync + 'static)>> { let mysql_connection = db_conn.mysql_connection().client.get_conn().await?; - let query_string = REGEX_DETECT_PARAMS.replace_all(&stmt, "?"); + let stmt_with_escape_characters = regex::escape(&stmt); + let query_string = REGEX_DETECT_PARAMS + .replace_all(&stmt_with_escape_characters, "?") + .to_string(); //TODO Temporal option, can produce error to save strings with quotes + println!("{:#?}", query_string); + let query_string = REGEX_DETECT_QUOTE + .replace_all(&query_string, "") + .to_string(); + println!("{:#?}", query_string); - let mut params_query: Vec = Vec::new(); - - for param in reorder_params_to_mysql(&stmt, params) { - params_query.push(from_value(param.as_mysql_param().to_value())); - } + let params_query: Vec = + reorder_params(&stmt, params, |f| f.as_mysql_param().to_value()); let query_with_params = QueryWithParams { - query: query_string.into_owned(), + query: query_string, params: params_query, }; let result: Vec = query_with_params.fetch(mysql_connection).await?; Ok(CanyonRows::MySQL(result)) } +} - pub fn reorder_params_to_mysql<'a, 'b, Z>( - stmt: &'b str, - params: Z, - ) -> Vec<&'a dyn QueryParameter<'a>> - where - Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, - { - let mut ordered_params = vec![]; - - for positional_param in REGEX_DETECT_PARAMS.find_iter(stmt) { - let pp = positional_param.as_str(); - let pp_index = pp[1..] - .parse::() - .expect("error parse mapped parameter to usized.") - - 1; - - let element = *params - .as_ref() - .get(pp_index) - .expect("error obtaining the element of the mapping against parameters."); - ordered_params.push(element); - } - - ordered_params +fn reorder_params( + stmt: &str, + params: &[&'_ dyn QueryParameter<'_>], + r#fn_parser: impl Fn(&dyn QueryParameter<'_>) -> T, +) -> Vec { + let mut ordered_params = vec![]; + + for positional_param in REGEX_DETECT_PARAMS.find_iter(stmt) { + let pp: &str = positional_param.as_str(); + let pp_index = pp[1..] + .parse::() + .expect("error parse mapped parameter to usized.") + - 1; + + let element = *params + .as_ref() + .get(pp_index) + .expect("error obtaining the element of the mapping against parameters."); + ordered_params.push(r#fn_parser(element)); } + + ordered_params } diff --git a/canyon_macros/src/utils/macro_tokens.rs b/canyon_macros/src/utils/macro_tokens.rs index eb2b4684..29de0467 100644 --- a/canyon_macros/src/utils/macro_tokens.rs +++ b/canyon_macros/src/utils/macro_tokens.rs @@ -92,7 +92,7 @@ impl<'a> MacroTokens<'a> { true } }) - .map(|c| format!("{}", c.ident.as_ref().unwrap())) + .map(|c| format!("\"{}\"", c.ident.as_ref().unwrap())) .collect::>() } From b1da9bbbb5496d1b6b681707b3cb26211473990c Mon Sep 17 00:00:00 2001 From: OnSystem Date: Mon, 21 Aug 2023 23:11:10 +0200 Subject: [PATCH 09/27] mysql-support select, update , and query_builder --- canyon_crud/src/crud.rs | 9 +- canyon_crud/src/query_elements/operators.rs | 23 ++++ canyon_macros/src/query_operations/insert.rs | 48 ++++++- tests/crud/delete_operations.rs | 52 +++++++- tests/crud/foreign_key_operations.rs | 55 +++++++- tests/crud/insert_operations.rs | 100 ++++++++++++++- tests/crud/querybuilder_operations.rs | 127 +++++++++++++++++-- 7 files changed, 393 insertions(+), 21 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 26709d32..2c65396e 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -255,14 +255,13 @@ mod mysql_query_launcher { let mysql_connection = db_conn.mysql_connection().client.get_conn().await?; let stmt_with_escape_characters = regex::escape(&stmt); - let query_string = REGEX_DETECT_PARAMS - .replace_all(&stmt_with_escape_characters, "?") - .to_string(); //TODO Temporal option, can produce error to save strings with quotes - println!("{:#?}", query_string); + let query_string = REGEX_DETECT_PARAMS.replace_all(&stmt_with_escape_characters, "?"); + let query_string = REGEX_DETECT_QUOTE .replace_all(&query_string, "") .to_string(); - println!("{:#?}", query_string); + + println!("{query_string}"); let params_query: Vec = reorder_params(&stmt, params, |f| f.as_mysql_param().to_value()); diff --git a/canyon_crud/src/query_elements/operators.rs b/canyon_crud/src/query_elements/operators.rs index 30637bad..44df931c 100644 --- a/canyon_crud/src/query_elements/operators.rs +++ b/canyon_crud/src/query_elements/operators.rs @@ -52,3 +52,26 @@ impl Operator for Like { } } } + +#[cfg(feature = "mysql")] +pub enum LikeMysql { + /// Operator "LIKE" as '%pattern%' + Full, + /// Operator "LIKE" as '%pattern' + Left, + /// Operator "LIKE" as 'pattern%' + Right, +} + +#[cfg(feature = "mysql")] +impl Operator for LikeMysql { + fn as_str(&self, placeholder_counter: usize) -> String { + match *self { + LikeMysql::Full => { + format!(" LIKE CONCAT('%', CAST(${placeholder_counter} AS CHAR) ,'%')") + } + LikeMysql::Left => format!(" LIKE CONCAT('%', CAST(${placeholder_counter} AS CHAR))"), + LikeMysql::Right => format!(" LIKE CONCAT(CAST(${placeholder_counter} AS CHAR) ,'%')"), + } + } +} diff --git a/canyon_macros/src/query_operations/insert.rs b/canyon_macros/src/query_operations/insert.rs index 329399f0..6e04a1b3 100644 --- a/canyon_macros/src/query_operations/insert.rs +++ b/canyon_macros/src/query_operations/insert.rs @@ -40,8 +40,9 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri let postgres_enabled = cfg!(feature = "postgres"); let mssql_enabled = cfg!(feature = "mssql"); + let mysql_enabled = cfg!(feature = "mysql"); - let match_rows = if postgres_enabled && mssql_enabled { + let match_rows = if postgres_enabled && mssql_enabled && mysql_enabled { quote! { canyon_sql::crud::CanyonRows::Postgres(mut v) => { self.#pk_ident = v @@ -58,6 +59,14 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri .ok_or("SQL Server primary key type failed to be set as value")?; Ok(()) } + canyon_sql::crud::CanyonRows::MySQL(mut v) => { + self.#pk_ident = v + .get(0) + .ok_or("Failed getting the returned IDs for a multi insert")? + .get::<#pk_type, &str>(#primary_key) + .ok_or("MYSQL primary key type failed to be set as value")?; + Ok(()) + } } } else if postgres_enabled { quote! { @@ -80,6 +89,17 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri Ok(()) } } + } else if mysql_enabled { + quote! { + canyon_sql::crud::CanyonRows::MySQL(mut v) => { + self.#pk_ident = v + .get(0) + .ok_or("Failed getting the returned IDs for a multi insert")? + .get::<#pk_type, &str>(#primary_key) + .ok_or("MYSQL primary key type failed to be set as value")?; + Ok(()) + } + } } else { quote! { panic!( @@ -261,8 +281,9 @@ pub fn generate_multiple_insert_tokens( let postgres_enabled = cfg!(feature = "postgres"); let mssql_enabled = cfg!(feature = "mssql"); + let mysql_enabled = cfg!(feature = "mysql"); - let match_multi_insert_rows = if postgres_enabled && mssql_enabled { + let match_multi_insert_rows = if postgres_enabled && mssql_enabled && mysql_enabled { quote! { canyon_sql::crud::CanyonRows::Postgres(mut v) => { for (idx, instance) in instances.iter_mut().enumerate() { @@ -285,6 +306,16 @@ pub fn generate_multiple_insert_tokens( Ok(()) } + canyon_sql::crud::CanyonRows::MySQL(mut v) => { + for (idx, instance) in instances.iter_mut().enumerate() { + instance.#pk_ident = v + .get(idx) + .expect("Failed getting the returned IDs for a multi insert") + .get::<#pk_type, &str>(#pk) + .expect("MYSQL primary key type failed to be set as value"); + } + Ok(()) + } } } else if postgres_enabled { quote! { @@ -310,6 +341,19 @@ pub fn generate_multiple_insert_tokens( .expect("SQL Server primary key type failed to be set as value"); } + Ok(()) + } + } + } else if mysql_enabled { + quote! { + canyon_sql::crud::CanyonRows::MySQL(mut v) => { + for (idx, instance) in instances.iter_mut().enumerate() { + instance.#pk_ident = v + .get(idx) + .expect("Failed getting the returned IDs for a multi insert") + .get::<#pk_type, &str>(#pk) + .expect("MYSQL primary key type failed to be set as value"); + } Ok(()) } } diff --git a/tests/crud/delete_operations.rs b/tests/crud/delete_operations.rs index 6420e553..31d1b0ef 100644 --- a/tests/crud/delete_operations.rs +++ b/tests/crud/delete_operations.rs @@ -2,10 +2,13 @@ ///! generates and executes *INSERT* statements use canyon_sql::crud::CrudOperations; +#[cfg(feature = "mysql")] +use crate::constants::MYSQL_DS; #[cfg(feature = "postgres")] use crate::constants::PSQL_DS; #[cfg(feature = "mssql")] use crate::constants::SQL_SERVER_DS; + use crate::tests_models::league::*; /// Deletes a row from the database that is mapped into some instance of a `T` entity. @@ -64,7 +67,7 @@ fn test_crud_delete_method_operation() { /// Same as the delete test, but performing the operations with the specified datasource #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_delete_datasource_method_operation() { +fn test_crud_delete_datasource_mssql_method_operation() { // For test the delete, we will insert a new instance of the database, and then, // after inspect it, we will proceed to delete it let mut new_league: League = League { @@ -107,3 +110,50 @@ fn test_crud_delete_datasource_method_operation() { None ); } + +/// Same as the delete test, but performing the operations with the specified datasource +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_delete_datasource_mysql_method_operation() { + // For test the delete, we will insert a new instance of the database, and then, + // after inspect it, we will proceed to delete it + let mut new_league: League = League { + id: Default::default(), + ext_id: 7892635306594_i64, + slug: "some-new-league".to_string(), + name: "Some New League".to_string(), + region: "Bahía de cochinos".to_string(), + image_url: "https://nobodyspectsandimage.io".to_string(), + }; + + // We insert the instance on the database, on the `League` entity + new_league + .insert_datasource(MYSQL_DS) + .await + .expect("Failed insert operation"); + assert_eq!( + new_league.id, + League::find_by_pk_datasource(&new_league.id, MYSQL_DS) + .await + .expect("Request error") + .expect("None value") + .id + ); + + // Now that we have an instance mapped to some entity by a primary key, we can now + // remove that entry from the database with the delete operation + new_league + .delete_datasource(MYSQL_DS) + .await + .expect("Failed to delete the operation"); + + // To check the success, we can query by the primary key value and check if, after unwrap() + // the result of the operation, the find by primary key contains Some(v) or None + // Remember that `find_by_primary_key(&dyn QueryParameter<'a>) -> Result>, Err> + assert_eq!( + League::find_by_pk_datasource(&new_league.id, MYSQL_DS) + .await + .expect("Unwrapping the result, letting the Option"), + None + ); +} diff --git a/tests/crud/foreign_key_operations.rs b/tests/crud/foreign_key_operations.rs index 471dd639..ad9368d5 100644 --- a/tests/crud/foreign_key_operations.rs +++ b/tests/crud/foreign_key_operations.rs @@ -10,8 +10,11 @@ ///! For more info: TODO -> Link to the docs of the foreign key chapter use canyon_sql::crud::CrudOperations; +#[cfg(feature = "mssql")] +use crate::constants::MYSQL_DS; #[cfg(feature = "mssql")] use crate::constants::SQL_SERVER_DS; + use crate::tests_models::league::*; use crate::tests_models::tournament::*; @@ -42,7 +45,7 @@ fn test_crud_search_by_foreign_key() { /// Same as the search by foreign key, but with the specified datasource #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_search_by_foreign_key_datasource() { +fn test_crud_search_by_foreign_key_datasource_mssql() { let some_tournament: Tournament = Tournament::find_by_pk_datasource(&10, SQL_SERVER_DS) .await .expect("Result variant of the query is err") @@ -65,6 +68,32 @@ fn test_crud_search_by_foreign_key_datasource() { } } +/// Same as the search by foreign key, but with the specified datasource +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_search_by_foreign_key_datasource_mysql() { + let some_tournament: Tournament = Tournament::find_by_pk_datasource(&10, MYSQL_DS) + .await + .expect("Result variant of the query is err") + .expect("No result found for the given parameter"); + + // We can get the parent entity for the retrieved child instance + let parent_entity: Option = some_tournament + .search_league_datasource(MYSQL_DS) + .await + .expect("Result variant of the query is err"); + + // These are tests, and we could unwrap the result contained in the option, because + // it always should exist that search for the data inserted when the docker starts. + // But, just for change the style a little bit and offer more options about how to + // handle things done with Canyon + if let Some(league) = parent_entity { + assert_eq!(some_tournament.league, league.id) + } else { + assert_eq!(parent_entity, None) + } +} + /// Given an entity `U` that is know as the "parent" side of the relation with another /// entity `T`, for example, we can ask to the parent for the childrens that belongs /// to `U`. @@ -93,7 +122,7 @@ fn test_crud_search_reverse_side_foreign_key() { /// but with the specified datasource #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_search_reverse_side_foreign_key_datasource() { +fn test_crud_search_reverse_side_foreign_key_datasource_mssql() { let some_league: League = League::find_by_pk_datasource(&1, SQL_SERVER_DS) .await .expect("Result variant of the query is err") @@ -110,3 +139,25 @@ fn test_crud_search_reverse_side_foreign_key_datasource() { .iter() .for_each(|t| assert_eq!(t.league, some_league.id)); } + +/// Same as the search by the reverse side of a foreign key relation +/// but with the specified datasource +#[cfg(feature = "mssql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_search_reverse_side_foreign_key_datasource_mysql() { + let some_league: League = League::find_by_pk_datasource(&1, MYSQL_DS) + .await + .expect("Result variant of the query is err") + .expect("No result found for the given parameter"); + + // Computes how many tournaments are pointing to the retrieved league + let child_tournaments: Vec = + Tournament::search_league_childrens_datasource(&some_league, MYSQL_DS) + .await + .expect("Result variant of the query is err"); + + assert!(!child_tournaments.is_empty()); + child_tournaments + .iter() + .for_each(|t| assert_eq!(t.league, some_league.id)); +} diff --git a/tests/crud/insert_operations.rs b/tests/crud/insert_operations.rs index d52fa868..b1946a84 100644 --- a/tests/crud/insert_operations.rs +++ b/tests/crud/insert_operations.rs @@ -2,6 +2,8 @@ ///! generates and executes *INSERT* statements use canyon_sql::crud::CrudOperations; +#[cfg(feature = "mysql")] +use crate::constants::MYSQL_DS; #[cfg(feature = "mssql")] use crate::constants::SQL_SERVER_DS; use crate::tests_models::league::*; @@ -58,7 +60,7 @@ fn test_crud_insert_operation() { /// the specified datasource #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_insert_datasource_operation() { +fn test_crud_insert_datasource_mssql_operation() { let mut new_league: League = League { id: Default::default(), ext_id: 7892635306594_i64, @@ -86,6 +88,38 @@ fn test_crud_insert_datasource_operation() { assert_eq!(new_league.id, inserted_league.id); } +/// Same as the insert operation above, but targeting the database defined in +/// the specified datasource +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_insert_datasource_mysql_operation() { + let mut new_league: League = League { + id: Default::default(), + ext_id: 7892635306594_i64, + slug: "some-new-league".to_string(), + name: "Some New League".to_string(), + region: "Bahía de cochinos".to_string(), + image_url: "https://nobodyspectsandimage.io".to_string(), + }; + + // We insert the instance on the database, on the `League` entity + new_league + .insert_datasource(MYSQL_DS) + .await + .expect("Failed insert datasource operation"); + + // Now, in the `id` field of the instance, we have the autogenerated + // value for the primary key field, which is id. So, we can query the + // database again with the find by primary key operation to check if + // the value was really inserted + let inserted_league = League::find_by_pk_datasource(&new_league.id, MYSQL_DS) + .await + .expect("Failed the query to the database") + .expect("No entity found for the primary key value passed in"); + + assert_eq!(new_league.id, inserted_league.id); +} + /// The multi insert operation is a shorthand for insert multiple instances of *T* /// in the database at once. /// @@ -160,7 +194,7 @@ fn test_crud_multi_insert_operation() { /// Same as the multi insert above, but with the specified datasource #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_multi_insert_datasource_operation() { +fn test_crud_multi_insert_datasource_mssql_operation() { let mut new_league_mi: League = League { id: Default::default(), ext_id: 54376478_i64, @@ -218,3 +252,65 @@ fn test_crud_multi_insert_datasource_operation() { assert_eq!(new_league_mi_2.id, inserted_league_2.id); assert_eq!(new_league_mi_3.id, inserted_league_3.id); } + +/// Same as the multi insert above, but with the specified datasource +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_multi_insert_datasource_mysql_operation() { + let mut new_league_mi: League = League { + id: Default::default(), + ext_id: 54376478_i64, + slug: "some-new-random-league".to_string(), + name: "Some New Random League".to_string(), + region: "Unknown".to_string(), + image_url: "https://what-a-league.io".to_string(), + }; + let mut new_league_mi_2: League = League { + id: Default::default(), + ext_id: 3475689769678906_i64, + slug: "new-league-2".to_string(), + name: "New League 2".to_string(), + region: "Really unknown".to_string(), + image_url: "https://what-an-unknown-league.io".to_string(), + }; + let mut new_league_mi_3: League = League { + id: Default::default(), + ext_id: 46756867_i64, + slug: "a-new-multinsert".to_string(), + name: "New League 3".to_string(), + region: "The dark side of the moon".to_string(), + image_url: "https://interplanetary-league.io".to_string(), + }; + + // Insert the instance as database entities + new_league_mi + .insert_datasource(MYSQL_DS) + .await + .expect("Failed insert datasource operation"); + new_league_mi_2 + .insert_datasource(MYSQL_DS) + .await + .expect("Failed insert datasource operation"); + new_league_mi_3 + .insert_datasource(MYSQL_DS) + .await + .expect("Failed insert datasource operation"); + + // Recover the inserted data by primary key + let inserted_league = League::find_by_pk_datasource(&new_league_mi.id, MYSQL_DS) + .await + .expect("[1] - Failed the query to the database") + .expect("[1] - No entity found for the primary key value passed in"); + let inserted_league_2 = League::find_by_pk_datasource(&new_league_mi_2.id, MYSQL_DS) + .await + .expect("[2] - Failed the query to the database") + .expect("[2] - No entity found for the primary key value passed in"); + let inserted_league_3 = League::find_by_pk_datasource(&new_league_mi_3.id, MYSQL_DS) + .await + .expect("[3] - Failed the query to the database") + .expect("[3] - No entity found for the primary key value passed in"); + + assert_eq!(new_league_mi.id, inserted_league.id); + assert_eq!(new_league_mi_2.id, inserted_league_2.id); + assert_eq!(new_league_mi_3.id, inserted_league_3.id); +} diff --git a/tests/crud/querybuilder_operations.rs b/tests/crud/querybuilder_operations.rs index 4bc205f6..ff368eb3 100644 --- a/tests/crud/querybuilder_operations.rs +++ b/tests/crud/querybuilder_operations.rs @@ -1,3 +1,8 @@ +#[cfg(feature = "mysql")] +use crate::constants::MYSQL_DS; +#[cfg(feature = "mssql")] +use crate::constants::SQL_SERVER_DS; +use canyon_sql::query::operators::LikeMysql; ///! Tests for the QueryBuilder available operations within Canyon. /// ///! QueryBuilder are the way of obtain more flexibility that with @@ -9,10 +14,7 @@ use canyon_sql::{ query::{operators::Comp, operators::Like, ops::QueryBuilder}, }; -#[cfg(feature = "mssql")] -use crate::constants::SQL_SERVER_DS; use crate::tests_models::league::*; -#[cfg(feature = "mssql")] use crate::tests_models::player::*; use crate::tests_models::tournament::*; @@ -78,7 +80,7 @@ fn test_crud_find_with_querybuilder_and_fulllike() { /// with the parameters that modifies the base SQL to SELECT * FROM #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_find_with_querybuilder_and_fulllike_datasource() { +fn test_crud_find_with_querybuilder_and_fulllike_datasource_mssql() { // Find all the leagues with "LC" in their name let mut filtered_leagues_result = League::select_query_datasource(SQL_SERVER_DS); filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), Like::Full); @@ -89,6 +91,21 @@ fn test_crud_find_with_querybuilder_and_fulllike_datasource() { ) } +/// Builds a new SQL statement for retrieves entities of the `T` type, filtered +/// with the parameters that modifies the base SQL to SELECT * FROM +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_find_with_querybuilder_and_fulllike_datasource_mysql() { + // Find all the leagues with "LC" in their name + let mut filtered_leagues_result = League::select_query_datasource(SQL_SERVER_DS); + filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), LikeMysql::Full); + + assert_eq!( + filtered_leagues_result.read_sql(), + "SELECT * FROM league WHERE name LIKE CONCAT('%', CAST($1 AS CHAR) ,'%')" + ) +} + /// Builds a new SQL statement for retrieves entities of the `T` type, filtered /// with the parameters that modifies the base SQL to SELECT * FROM #[cfg(feature = "postgres")] @@ -108,7 +125,7 @@ fn test_crud_find_with_querybuilder_and_leftlike() { /// with the parameters that modifies the base SQL to SELECT * FROM #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_find_with_querybuilder_and_leftlike_datasource() { +fn test_crud_find_with_querybuilder_and_leftlike_datasource_mssql() { // Find all the leagues whose name ends with "CK" let mut filtered_leagues_result = League::select_query(); filtered_leagues_result.r#where(LeagueFieldValue::name(&"CK"), Like::Left); @@ -119,6 +136,21 @@ fn test_crud_find_with_querybuilder_and_leftlike_datasource() { ) } +/// Builds a new SQL statement for retrieves entities of the `T` type, filtered +/// with the parameters that modifies the base SQL to SELECT * FROM +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_find_with_querybuilder_and_leftlike_datasource_mysql() { + // Find all the leagues whose name ends with "CK" + let mut filtered_leagues_result = League::select_query(); + filtered_leagues_result.r#where(LeagueFieldValue::name(&"CK"), LikeMysql::Left); + + assert_eq!( + filtered_leagues_result.read_sql(), + "SELECT * FROM league WHERE name LIKE CONCAT('%', CAST($1 AS CHAR))" + ) +} + /// Builds a new SQL statement for retrieves entities of the `T` type, filtered /// with the parameters that modifies the base SQL to SELECT * FROM #[cfg(feature = "postgres")] @@ -138,7 +170,7 @@ fn test_crud_find_with_querybuilder_and_rightlike() { /// with the parameters that modifies the base SQL to SELECT * FROM #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_find_with_querybuilder_and_rightlike_datasource() { +fn test_crud_find_with_querybuilder_and_rightlike_datasource_mssql() { // Find all the leagues whose name starts with "LC" let mut filtered_leagues_result = League::select_query_datasource(SQL_SERVER_DS); filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), Like::Right); @@ -148,11 +180,38 @@ fn test_crud_find_with_querybuilder_and_rightlike_datasource() { "SELECT * FROM league WHERE name LIKE CONCAT(CAST($1 AS VARCHAR) ,'%')" ) } +/// Builds a new SQL statement for retrieves entities of the `T` type, filtered +/// with the parameters that modifies the base SQL to SELECT * FROM +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_find_with_querybuilder_and_rightlike_datasource_mysql() { + // Find all the leagues whose name starts with "LC" + let mut filtered_leagues_result = League::select_query_datasource(SQL_SERVER_DS); + filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), LikeMysql::Right); + + assert_eq!( + filtered_leagues_result.read_sql(), + "SELECT * FROM league WHERE name LIKE CONCAT(CAST($1 AS CHAR) ,'%')" + ) +} /// Same than the above but with the specified datasource #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_find_with_querybuilder_datasource() { +fn test_crud_find_with_querybuilder_datasource_mssql() { + // Find all the players where its ID column value is greater that 50 + let filtered_find_players = Player::select_query_datasource(SQL_SERVER_DS) + .r#where(PlayerFieldValue::id(&50), Comp::Gt) + .query() + .await; + + assert!(!filtered_find_players.unwrap().is_empty()); +} + +/// Same than the above but with the specified datasource +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_find_with_querybuilder_datasource_mysql() { // Find all the players where its ID column value is greater that 50 let filtered_find_players = Player::select_query_datasource(SQL_SERVER_DS) .r#where(PlayerFieldValue::id(&50), Comp::Gt) @@ -202,7 +261,7 @@ fn test_crud_update_with_querybuilder() { /// Same as above, but with the specified datasource #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_update_with_querybuilder_datasource() { +fn test_crud_update_with_querybuilder_datasource_mssql() { // Find all the leagues with ID less or equals that 7 // and where it's region column value is equals to 'Korea' let mut q = Player::update_query_datasource(SQL_SERVER_DS); @@ -229,6 +288,37 @@ fn test_crud_update_with_querybuilder_datasource() { }); } +/// Same as above, but with the specified datasource +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_update_with_querybuilder_datasource_mysql() { + // Find all the leagues with ID less or equals that 7 + // and where it's region column value is equals to 'Korea' + + let mut q = Player::update_query_datasource(MYSQL_DS); + q.set(&[ + (PlayerField::summoner_name, "Random updated player name"), + (PlayerField::first_name, "I am an updated first name"), + ]) + .r#where(PlayerFieldValue::id(&1), Comp::Gt) + .and(PlayerFieldValue::id(&8), Comp::Lt) + .query() + .await + .expect("Failed to update records with the querybuilder"); + + let found_updated_values = Player::select_query_datasource(MYSQL_DS) + .r#where(PlayerFieldValue::id(&1), Comp::Gt) + .and(PlayerFieldValue::id(&7), Comp::LtEq) + .query() + .await + .expect("Failed to retrieve database League entries with the querybuilder"); + + found_updated_values.iter().for_each(|player| { + assert_eq!(player.summoner_name, "Random updated player name"); + assert_eq!(player.first_name, "I am an updated first name"); + }); +} + /// Deletes entries from the mapped entity `T` that are in the ranges filtered /// with the QueryBuilder /// @@ -251,7 +341,7 @@ fn test_crud_delete_with_querybuilder() { /// Same as the above delete, but with the specified datasource #[cfg(feature = "mssql")] #[canyon_sql::macros::canyon_tokio_test] -fn test_crud_delete_with_querybuilder_datasource() { +fn test_crud_delete_with_querybuilder_datasource_mssql() { Player::delete_query_datasource(SQL_SERVER_DS) .r#where(PlayerFieldValue::id(&120), Comp::Gt) .and(PlayerFieldValue::id(&130), Comp::Lt) @@ -267,6 +357,25 @@ fn test_crud_delete_with_querybuilder_datasource() { .is_empty()); } +/// Same as the above delete, but with the specified datasource +#[cfg(feature = "mysql")] +#[canyon_sql::macros::canyon_tokio_test] +fn test_crud_delete_with_querybuilder_datasource_mysql() { + Player::delete_query_datasource(MYSQL_DS) + .r#where(PlayerFieldValue::id(&120), Comp::Gt) + .and(PlayerFieldValue::id(&130), Comp::Lt) + .query() + .await + .expect("Error connecting with the database when we are going to delete data! :)"); + + assert!(Player::select_query_datasource(MYSQL_DS) + .r#where(PlayerFieldValue::id(&122), Comp::Eq) + .query() + .await + .unwrap() + .is_empty()); +} + /// Tests for the generated SQL query after use the /// WHERE clause #[canyon_sql::macros::canyon_tokio_test] From b3164c64346b74833e82ebb56695c4f035ee6ebd Mon Sep 17 00:00:00 2001 From: onsystem Date: Thu, 31 Aug 2023 22:58:11 +0200 Subject: [PATCH 10/27] mysql-support correction test insert and delete mysql implementation and investigate get last insert in mysql_async --- canyon_crud/src/crud.rs | 18 +++++- canyon_macros/src/query_operations/insert.rs | 10 +++- tests/crud/delete_operations.rs | 32 +++-------- tests/crud/insert_operations.rs | 60 ++++++-------------- 4 files changed, 50 insertions(+), 70 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 2c65396e..b06a2a9f 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -257,11 +257,14 @@ mod mysql_query_launcher { let stmt_with_escape_characters = regex::escape(&stmt); let query_string = REGEX_DETECT_PARAMS.replace_all(&stmt_with_escape_characters, "?"); - let query_string = REGEX_DETECT_QUOTE + let mut query_string = REGEX_DETECT_QUOTE .replace_all(&query_string, "") .to_string(); - println!("{query_string}"); + //In mysql isn`t support RETURNING clause in insert operation + if let Some(index_start_clausule_returning) = query_string.find(" RETURNING") { + query_string.truncate(index_start_clausule_returning); + } let params_query: Vec = reorder_params(&stmt, params, |f| f.as_mysql_param().to_value()); @@ -271,7 +274,16 @@ mod mysql_query_launcher { params: params_query, }; - let result: Vec = query_with_params.fetch(mysql_connection).await?; + let mut query_result = query_with_params + .run(mysql_connection) + .await + .expect("Error executing query in mysql"); + + let result = query_result + .collect() + .await + .expect("Error resolved trait FromRow in mysql"); + Ok(CanyonRows::MySQL(result)) } } diff --git a/canyon_macros/src/query_operations/insert.rs b/canyon_macros/src/query_operations/insert.rs index 6e04a1b3..72638974 100644 --- a/canyon_macros/src/query_operations/insert.rs +++ b/canyon_macros/src/query_operations/insert.rs @@ -60,11 +60,13 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri Ok(()) } canyon_sql::crud::CanyonRows::MySQL(mut v) => { + /* self.#pk_ident = v .get(0) .ok_or("Failed getting the returned IDs for a multi insert")? .get::<#pk_type, &str>(#primary_key) .ok_or("MYSQL primary key type failed to be set as value")?; + */ Ok(()) } } @@ -92,11 +94,13 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri } else if mysql_enabled { quote! { canyon_sql::crud::CanyonRows::MySQL(mut v) => { + /* self.#pk_ident = v .get(0) .ok_or("Failed getting the returned IDs for a multi insert")? .get::<#pk_type, &str>(#primary_key) .ok_or("MYSQL primary key type failed to be set as value")?; + */ Ok(()) } } @@ -307,6 +311,7 @@ pub fn generate_multiple_insert_tokens( Ok(()) } canyon_sql::crud::CanyonRows::MySQL(mut v) => { + /* for (idx, instance) in instances.iter_mut().enumerate() { instance.#pk_ident = v .get(idx) @@ -314,6 +319,7 @@ pub fn generate_multiple_insert_tokens( .get::<#pk_type, &str>(#pk) .expect("MYSQL primary key type failed to be set as value"); } + */ Ok(()) } } @@ -347,13 +353,15 @@ pub fn generate_multiple_insert_tokens( } else if mysql_enabled { quote! { canyon_sql::crud::CanyonRows::MySQL(mut v) => { + /* for (idx, instance) in instances.iter_mut().enumerate() { instance.#pk_ident = v - .get(idx) + .get(idx).or_else(vec![]) .expect("Failed getting the returned IDs for a multi insert") .get::<#pk_type, &str>(#pk) .expect("MYSQL primary key type failed to be set as value"); } + */ Ok(()) } } diff --git a/tests/crud/delete_operations.rs b/tests/crud/delete_operations.rs index 31d1b0ef..1317ac22 100644 --- a/tests/crud/delete_operations.rs +++ b/tests/crud/delete_operations.rs @@ -2,6 +2,8 @@ ///! generates and executes *INSERT* statements use canyon_sql::crud::CrudOperations; +use canyon_connection::{get_database_connection, CACHED_DATABASE_CONN}; + #[cfg(feature = "mysql")] use crate::constants::MYSQL_DS; #[cfg(feature = "postgres")] @@ -115,8 +117,11 @@ fn test_crud_delete_datasource_mssql_method_operation() { #[cfg(feature = "mysql")] #[canyon_sql::macros::canyon_tokio_test] fn test_crud_delete_datasource_mysql_method_operation() { + use crate::canyon_sql::db_clients::mysql_async::prelude::Query; + use crate::canyon_sql::db_clients::mysql_async::Row; // For test the delete, we will insert a new instance of the database, and then, // after inspect it, we will proceed to delete it + let mut new_league: League = League { id: Default::default(), ext_id: 7892635306594_i64, @@ -131,29 +136,10 @@ fn test_crud_delete_datasource_mysql_method_operation() { .insert_datasource(MYSQL_DS) .await .expect("Failed insert operation"); - assert_eq!( - new_league.id, - League::find_by_pk_datasource(&new_league.id, MYSQL_DS) - .await - .expect("Request error") - .expect("None value") - .id - ); - // Now that we have an instance mapped to some entity by a primary key, we can now - // remove that entry from the database with the delete operation - new_league - .delete_datasource(MYSQL_DS) - .await - .expect("Failed to delete the operation"); + // In mysql now cant get primary key + let result_delete = new_league.delete_datasource(MYSQL_DS).await; - // To check the success, we can query by the primary key value and check if, after unwrap() - // the result of the operation, the find by primary key contains Some(v) or None - // Remember that `find_by_primary_key(&dyn QueryParameter<'a>) -> Result>, Err> - assert_eq!( - League::find_by_pk_datasource(&new_league.id, MYSQL_DS) - .await - .expect("Unwrapping the result, letting the Option"), - None - ); + // Cant get last insert with need require call in now connection, if call in new connection return zero all time + assert!(result_delete.is_ok(), "Failed to delete the operation"); } diff --git a/tests/crud/insert_operations.rs b/tests/crud/insert_operations.rs index b1946a84..71673396 100644 --- a/tests/crud/insert_operations.rs +++ b/tests/crud/insert_operations.rs @@ -103,21 +103,9 @@ fn test_crud_insert_datasource_mysql_operation() { }; // We insert the instance on the database, on the `League` entity - new_league - .insert_datasource(MYSQL_DS) - .await - .expect("Failed insert datasource operation"); - - // Now, in the `id` field of the instance, we have the autogenerated - // value for the primary key field, which is id. So, we can query the - // database again with the find by primary key operation to check if - // the value was really inserted - let inserted_league = League::find_by_pk_datasource(&new_league.id, MYSQL_DS) - .await - .expect("Failed the query to the database") - .expect("No entity found for the primary key value passed in"); + let result = new_league.insert_datasource(MYSQL_DS).await; - assert_eq!(new_league.id, inserted_league.id); + assert!(result.is_ok()); } /// The multi insert operation is a shorthand for insert multiple instances of *T* @@ -283,34 +271,20 @@ fn test_crud_multi_insert_datasource_mysql_operation() { }; // Insert the instance as database entities - new_league_mi - .insert_datasource(MYSQL_DS) - .await - .expect("Failed insert datasource operation"); - new_league_mi_2 - .insert_datasource(MYSQL_DS) - .await - .expect("Failed insert datasource operation"); - new_league_mi_3 - .insert_datasource(MYSQL_DS) - .await - .expect("Failed insert datasource operation"); + let first_insert = new_league_mi.insert().await; + let second_insert = new_league_mi_2.insert().await; + let three_insert = new_league_mi_3.insert().await; - // Recover the inserted data by primary key - let inserted_league = League::find_by_pk_datasource(&new_league_mi.id, MYSQL_DS) - .await - .expect("[1] - Failed the query to the database") - .expect("[1] - No entity found for the primary key value passed in"); - let inserted_league_2 = League::find_by_pk_datasource(&new_league_mi_2.id, MYSQL_DS) - .await - .expect("[2] - Failed the query to the database") - .expect("[2] - No entity found for the primary key value passed in"); - let inserted_league_3 = League::find_by_pk_datasource(&new_league_mi_3.id, MYSQL_DS) - .await - .expect("[3] - Failed the query to the database") - .expect("[3] - No entity found for the primary key value passed in"); - - assert_eq!(new_league_mi.id, inserted_league.id); - assert_eq!(new_league_mi_2.id, inserted_league_2.id); - assert_eq!(new_league_mi_3.id, inserted_league_3.id); + assert!( + first_insert.is_ok(), + "Failed first insert datasource operation" + ); + assert!( + second_insert.is_ok(), + "Failed second insert datasource operation" + ); + assert!( + three_insert.is_ok(), + "Failed three insert datasource operation" + ) } From 39bfa884cc9b20e8c958d241c68932a1edc2cb74 Mon Sep 17 00:00:00 2001 From: onsystem Date: Thu, 31 Aug 2023 23:04:46 +0200 Subject: [PATCH 11/27] develop remove imports not use --- tests/crud/delete_operations.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/crud/delete_operations.rs b/tests/crud/delete_operations.rs index 1317ac22..f03b543c 100644 --- a/tests/crud/delete_operations.rs +++ b/tests/crud/delete_operations.rs @@ -2,8 +2,6 @@ ///! generates and executes *INSERT* statements use canyon_sql::crud::CrudOperations; -use canyon_connection::{get_database_connection, CACHED_DATABASE_CONN}; - #[cfg(feature = "mysql")] use crate::constants::MYSQL_DS; #[cfg(feature = "postgres")] @@ -117,8 +115,6 @@ fn test_crud_delete_datasource_mssql_method_operation() { #[cfg(feature = "mysql")] #[canyon_sql::macros::canyon_tokio_test] fn test_crud_delete_datasource_mysql_method_operation() { - use crate::canyon_sql::db_clients::mysql_async::prelude::Query; - use crate::canyon_sql::db_clients::mysql_async::Row; // For test the delete, we will insert a new instance of the database, and then, // after inspect it, we will proceed to delete it From 9ce698ccb42a59fbe9988cfdb4e116d1726eba49 Mon Sep 17 00:00:00 2001 From: onsystem Date: Sun, 3 Sep 2023 00:01:22 +0200 Subject: [PATCH 12/27] mysql-support added integration to returning primary key --- canyon_crud/src/bounds.rs | 5 +- canyon_crud/src/crud.rs | 24 ++++-- canyon_crud/src/mapper.rs | 4 +- canyon_crud/src/rows.rs | 81 +++++++++++++++++++- canyon_macros/src/lib.rs | 4 +- canyon_macros/src/query_operations/insert.rs | 18 ++--- tests/crud/delete_operations.rs | 28 +++++-- tests/crud/insert_operations.rs | 60 +++++++++++---- 8 files changed, 174 insertions(+), 50 deletions(-) diff --git a/canyon_crud/src/bounds.rs b/canyon_crud/src/bounds.rs index a75b3cac..aac728d4 100644 --- a/canyon_crud/src/bounds.rs +++ b/canyon_crud/src/bounds.rs @@ -1,8 +1,9 @@ +#[cfg(feature = "mysql")] +use crate::rows::mysql::CanyonRowMysql; use crate::{ crud::{CrudOperations, Transaction}, mapper::RowMapper, }; - #[cfg(feature = "mysql")] use canyon_connection::mysql_async::{self, prelude::ToValue}; @@ -104,7 +105,7 @@ impl Row for tiberius::Row { } #[cfg(feature = "mysql")] -impl Row for mysql_async::Row { +impl Row for CanyonRowMysql { fn as_any(&self) -> &dyn Any { self } diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index b06a2a9f..90720a9c 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -234,6 +234,8 @@ mod sqlserver_query_launcher { #[cfg(feature = "mysql")] mod mysql_query_launcher { + use std::sync::Arc; + use canyon_connection::canyon_database_connector::DatabaseConnection; use mysql_async::prelude::Query; @@ -242,6 +244,7 @@ mod mysql_query_launcher { use crate::bounds::QueryParameter; use crate::crud::REGEX_DETECT_QUOTE; + use crate::rows::mysql::CanyonRowMysql; use crate::rows::CanyonRows; use super::reorder_params; @@ -261,9 +264,11 @@ mod mysql_query_launcher { .replace_all(&query_string, "") .to_string(); + let mut is_insert = false; //In mysql isn`t support RETURNING clause in insert operation if let Some(index_start_clausule_returning) = query_string.find(" RETURNING") { query_string.truncate(index_start_clausule_returning); + is_insert = true; } let params_query: Vec = @@ -279,19 +284,24 @@ mod mysql_query_launcher { .await .expect("Error executing query in mysql"); - let result = query_result - .collect() - .await - .expect("Error resolved trait FromRow in mysql"); + let result_rows = if is_insert { + let last_insert = query_result.last_insert_id().map(Value::UInt); + vec![CanyonRowMysql::new(vec![last_insert], Arc::new([]))] + } else { + query_result + .map(CanyonRowMysql::from) + .await + .expect("Error resolved trait FromRow in mysql") + }; - Ok(CanyonRows::MySQL(result)) + Ok(CanyonRows::MySQL(result_rows)) } } fn reorder_params( stmt: &str, params: &[&'_ dyn QueryParameter<'_>], - r#fn_parser: impl Fn(&dyn QueryParameter<'_>) -> T, + fn_parser: impl Fn(&dyn QueryParameter<'_>) -> T, ) -> Vec { let mut ordered_params = vec![]; @@ -306,7 +316,7 @@ fn reorder_params( .as_ref() .get(pp_index) .expect("error obtaining the element of the mapping against parameters."); - ordered_params.push(r#fn_parser(element)); + ordered_params.push(fn_parser(element)); } ordered_params diff --git a/canyon_crud/src/mapper.rs b/canyon_crud/src/mapper.rs index 252df1ce..2d8b9e1d 100644 --- a/canyon_crud/src/mapper.rs +++ b/canyon_crud/src/mapper.rs @@ -1,5 +1,5 @@ #[cfg(feature = "mysql")] -use canyon_connection::mysql_async; +use crate::rows::mysql::CanyonRowMysql; #[cfg(feature = "mssql")] use canyon_connection::tiberius; #[cfg(feature = "postgres")] @@ -16,5 +16,5 @@ pub trait RowMapper>: Sized { #[cfg(feature = "mssql")] fn deserialize_sqlserver(row: &tiberius::Row) -> T; #[cfg(feature = "mysql")] - fn deserialize_mysql(row: &mysql_async::Row) -> T; + fn deserialize_mysql(row: &CanyonRowMysql) -> T; } diff --git a/canyon_crud/src/rows.rs b/canyon_crud/src/rows.rs index 517592a6..23b0cd5d 100644 --- a/canyon_crud/src/rows.rs +++ b/canyon_crud/src/rows.rs @@ -14,7 +14,7 @@ pub enum CanyonRows { #[cfg(feature = "mssql")] Tiberius(Vec), #[cfg(feature = "mysql")] - MySQL(Vec), + MySQL(Vec), UnusableTypeMarker(PhantomData), } @@ -37,7 +37,7 @@ impl CanyonRows { } #[cfg(feature = "mysql")] - pub fn get_mysql_rows(&self) -> &Vec { + pub fn get_mysql_rows(&self) -> &Vec { match self { Self::MySQL(v) => v, _ => panic!("This branch will never ever should be reachable"), @@ -86,3 +86,80 @@ impl CanyonRows { } } } + +#[cfg(feature = "mysql")] +pub mod mysql { + use mysql_async::{from_value, Column, Value}; + use mysql_common::{prelude::FromValue, row::ColumnIndex, Row}; + use std::{ops::Index, sync::Arc}; + + #[derive(Debug)] + pub struct CanyonRowMysql { + values: Vec>, + columns: Arc<[Column]>, + } + + impl CanyonRowMysql { + pub fn new(values: Vec>, columns: Arc<[Column]>) -> Self { + Self { values, columns } + } + + pub fn get(&self, index: I) -> Option + where + T: FromValue, + I: ColumnIndex, + { + index.idx(&self.columns).and_then(|idx| { + self.values + .get(idx) + .and_then(|x| x.as_ref()) + .map(|x| from_value::(x.clone())) + }) + } + pub fn get_by_index(&self, index: usize) -> Option + where + T: FromValue, + //I: ColumnIndex, + { + //TODO + self.values + .get(index) + .and_then(|x| x.as_ref()) + .map(|v| from_value::(v.clone())) + } + } + + impl From for CanyonRowMysql { + fn from(value: Row) -> Self { + Self { + values: value + .columns() + .iter() + .map(|c| value.get(c.name_str().as_ref())) //TODO + .collect(), + columns: value.columns(), + } + } + } + + impl Index for CanyonRowMysql { + type Output = Value; + + fn index(&self, index: usize) -> &Value { + self.values[index].as_ref().unwrap() + } + } + + impl<'a> Index<&'a str> for CanyonRowMysql { + type Output = Value; + + fn index<'r>(&'r self, index: &'a str) -> &'r Value { + for (i, column) in self.columns.iter().enumerate() { + if column.name_ref() == index.as_bytes() { + return self.values[i].as_ref().unwrap(); + } + } + panic!("No such column: `{}` in row {:?}", index, self); + } + } +} diff --git a/canyon_macros/src/lib.rs b/canyon_macros/src/lib.rs index 3eae3d99..9549570f 100755 --- a/canyon_macros/src/lib.rs +++ b/canyon_macros/src/lib.rs @@ -558,7 +558,7 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac #(#init_field_values_sqlserver),* } } - fn deserialize_mysql(row: &canyon_sql::db_clients::mysql_async::Row) -> #ty { + fn deserialize_mysql(row: &canyon_crud::rows::mysql::CanyonRowMysql) -> #ty { Self { #(#init_field_values_mysql),* } @@ -588,7 +588,7 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac } else if mysql_enabled { quote! { impl canyon_sql::crud::RowMapper for #ty { - fn deserialize_mysql(row: &canyon_sql::db_clients::mysql_async::Row) -> #ty { + fn deserialize_mysql(row: &canyon_crud::rows::mysql::CanyonRowMysql) -> #ty { Self { #(#init_field_values_mysql),* } diff --git a/canyon_macros/src/query_operations/insert.rs b/canyon_macros/src/query_operations/insert.rs index 72638974..5c97f66c 100644 --- a/canyon_macros/src/query_operations/insert.rs +++ b/canyon_macros/src/query_operations/insert.rs @@ -60,13 +60,11 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri Ok(()) } canyon_sql::crud::CanyonRows::MySQL(mut v) => { - /* self.#pk_ident = v .get(0) .ok_or("Failed getting the returned IDs for a multi insert")? - .get::<#pk_type, &str>(#primary_key) + .get_by_index::<#pk_type>(0) .ok_or("MYSQL primary key type failed to be set as value")?; - */ Ok(()) } } @@ -94,13 +92,11 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri } else if mysql_enabled { quote! { canyon_sql::crud::CanyonRows::MySQL(mut v) => { - /* self.#pk_ident = v .get(0) .ok_or("Failed getting the returned IDs for a multi insert")? - .get::<#pk_type, &str>(#primary_key) + .get_by_index::<#pk_type>(0) .ok_or("MYSQL primary key type failed to be set as value")?; - */ Ok(()) } } @@ -311,15 +307,13 @@ pub fn generate_multiple_insert_tokens( Ok(()) } canyon_sql::crud::CanyonRows::MySQL(mut v) => { - /* for (idx, instance) in instances.iter_mut().enumerate() { instance.#pk_ident = v .get(idx) .expect("Failed getting the returned IDs for a multi insert") - .get::<#pk_type, &str>(#pk) + .get_by_index::<#pk_type>(0) .expect("MYSQL primary key type failed to be set as value"); } - */ Ok(()) } } @@ -353,15 +347,13 @@ pub fn generate_multiple_insert_tokens( } else if mysql_enabled { quote! { canyon_sql::crud::CanyonRows::MySQL(mut v) => { - /* for (idx, instance) in instances.iter_mut().enumerate() { instance.#pk_ident = v - .get(idx).or_else(vec![]) + .get(idx) .expect("Failed getting the returned IDs for a multi insert") - .get::<#pk_type, &str>(#pk) + .get_by_index::<#pk_type>(0) .expect("MYSQL primary key type failed to be set as value"); } - */ Ok(()) } } diff --git a/tests/crud/delete_operations.rs b/tests/crud/delete_operations.rs index f03b543c..31d1b0ef 100644 --- a/tests/crud/delete_operations.rs +++ b/tests/crud/delete_operations.rs @@ -117,7 +117,6 @@ fn test_crud_delete_datasource_mssql_method_operation() { fn test_crud_delete_datasource_mysql_method_operation() { // For test the delete, we will insert a new instance of the database, and then, // after inspect it, we will proceed to delete it - let mut new_league: League = League { id: Default::default(), ext_id: 7892635306594_i64, @@ -132,10 +131,29 @@ fn test_crud_delete_datasource_mysql_method_operation() { .insert_datasource(MYSQL_DS) .await .expect("Failed insert operation"); + assert_eq!( + new_league.id, + League::find_by_pk_datasource(&new_league.id, MYSQL_DS) + .await + .expect("Request error") + .expect("None value") + .id + ); - // In mysql now cant get primary key - let result_delete = new_league.delete_datasource(MYSQL_DS).await; + // Now that we have an instance mapped to some entity by a primary key, we can now + // remove that entry from the database with the delete operation + new_league + .delete_datasource(MYSQL_DS) + .await + .expect("Failed to delete the operation"); - // Cant get last insert with need require call in now connection, if call in new connection return zero all time - assert!(result_delete.is_ok(), "Failed to delete the operation"); + // To check the success, we can query by the primary key value and check if, after unwrap() + // the result of the operation, the find by primary key contains Some(v) or None + // Remember that `find_by_primary_key(&dyn QueryParameter<'a>) -> Result>, Err> + assert_eq!( + League::find_by_pk_datasource(&new_league.id, MYSQL_DS) + .await + .expect("Unwrapping the result, letting the Option"), + None + ); } diff --git a/tests/crud/insert_operations.rs b/tests/crud/insert_operations.rs index 71673396..b1946a84 100644 --- a/tests/crud/insert_operations.rs +++ b/tests/crud/insert_operations.rs @@ -103,9 +103,21 @@ fn test_crud_insert_datasource_mysql_operation() { }; // We insert the instance on the database, on the `League` entity - let result = new_league.insert_datasource(MYSQL_DS).await; + new_league + .insert_datasource(MYSQL_DS) + .await + .expect("Failed insert datasource operation"); + + // Now, in the `id` field of the instance, we have the autogenerated + // value for the primary key field, which is id. So, we can query the + // database again with the find by primary key operation to check if + // the value was really inserted + let inserted_league = League::find_by_pk_datasource(&new_league.id, MYSQL_DS) + .await + .expect("Failed the query to the database") + .expect("No entity found for the primary key value passed in"); - assert!(result.is_ok()); + assert_eq!(new_league.id, inserted_league.id); } /// The multi insert operation is a shorthand for insert multiple instances of *T* @@ -271,20 +283,34 @@ fn test_crud_multi_insert_datasource_mysql_operation() { }; // Insert the instance as database entities - let first_insert = new_league_mi.insert().await; - let second_insert = new_league_mi_2.insert().await; - let three_insert = new_league_mi_3.insert().await; + new_league_mi + .insert_datasource(MYSQL_DS) + .await + .expect("Failed insert datasource operation"); + new_league_mi_2 + .insert_datasource(MYSQL_DS) + .await + .expect("Failed insert datasource operation"); + new_league_mi_3 + .insert_datasource(MYSQL_DS) + .await + .expect("Failed insert datasource operation"); - assert!( - first_insert.is_ok(), - "Failed first insert datasource operation" - ); - assert!( - second_insert.is_ok(), - "Failed second insert datasource operation" - ); - assert!( - three_insert.is_ok(), - "Failed three insert datasource operation" - ) + // Recover the inserted data by primary key + let inserted_league = League::find_by_pk_datasource(&new_league_mi.id, MYSQL_DS) + .await + .expect("[1] - Failed the query to the database") + .expect("[1] - No entity found for the primary key value passed in"); + let inserted_league_2 = League::find_by_pk_datasource(&new_league_mi_2.id, MYSQL_DS) + .await + .expect("[2] - Failed the query to the database") + .expect("[2] - No entity found for the primary key value passed in"); + let inserted_league_3 = League::find_by_pk_datasource(&new_league_mi_3.id, MYSQL_DS) + .await + .expect("[3] - Failed the query to the database") + .expect("[3] - No entity found for the primary key value passed in"); + + assert_eq!(new_league_mi.id, inserted_league.id); + assert_eq!(new_league_mi_2.id, inserted_league_2.id); + assert_eq!(new_league_mi_3.id, inserted_league_3.id); } From 9d469769b075ddfed398e7a3e659cbb42b5c9e73 Mon Sep 17 00:00:00 2001 From: onsystem Date: Tue, 19 Sep 2023 23:20:05 +0200 Subject: [PATCH 13/27] mysql-support correction cfg features --- canyon_crud/src/bounds.rs | 5 ++--- canyon_crud/src/crud.rs | 2 +- tests/crud/foreign_key_operations.rs | 2 +- tests/crud/insert_operations.rs | 1 + tests/crud/querybuilder_operations.rs | 1 + tests/crud/update_operations.rs | 3 +-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/canyon_crud/src/bounds.rs b/canyon_crud/src/bounds.rs index aac728d4..91c869b1 100644 --- a/canyon_crud/src/bounds.rs +++ b/canyon_crud/src/bounds.rs @@ -1,12 +1,11 @@ -#[cfg(feature = "mysql")] -use crate::rows::mysql::CanyonRowMysql; use crate::{ crud::{CrudOperations, Transaction}, mapper::RowMapper, }; #[cfg(feature = "mysql")] use canyon_connection::mysql_async::{self, prelude::ToValue}; - +#[cfg(feature = "mysql")] +use crate::rows::mysql::CanyonRowMysql; #[cfg(feature = "mssql")] use canyon_connection::tiberius::{self, ColumnData, IntoSql}; #[cfg(feature = "postgres")] diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 90720a9c..02db7830 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -60,7 +60,7 @@ pub trait Transaction { ) .await } - #[cfg(feature = "mssql")] + #[cfg(feature = "mysql")] DatabaseConnection::MySQL(_) => { mysql_query_launcher::launch::(database_conn, stmt.to_string(), params.as_ref()) .await diff --git a/tests/crud/foreign_key_operations.rs b/tests/crud/foreign_key_operations.rs index ad9368d5..21cae200 100644 --- a/tests/crud/foreign_key_operations.rs +++ b/tests/crud/foreign_key_operations.rs @@ -142,7 +142,7 @@ fn test_crud_search_reverse_side_foreign_key_datasource_mssql() { /// Same as the search by the reverse side of a foreign key relation /// but with the specified datasource -#[cfg(feature = "mssql")] +#[cfg(feature = "mysql")] #[canyon_sql::macros::canyon_tokio_test] fn test_crud_search_reverse_side_foreign_key_datasource_mysql() { let some_league: League = League::find_by_pk_datasource(&1, MYSQL_DS) diff --git a/tests/crud/insert_operations.rs b/tests/crud/insert_operations.rs index b1946a84..898182b6 100644 --- a/tests/crud/insert_operations.rs +++ b/tests/crud/insert_operations.rs @@ -6,6 +6,7 @@ use canyon_sql::crud::CrudOperations; use crate::constants::MYSQL_DS; #[cfg(feature = "mssql")] use crate::constants::SQL_SERVER_DS; + use crate::tests_models::league::*; /// Inserts a new record on the database, given an entity that is diff --git a/tests/crud/querybuilder_operations.rs b/tests/crud/querybuilder_operations.rs index ff368eb3..8516d3e9 100644 --- a/tests/crud/querybuilder_operations.rs +++ b/tests/crud/querybuilder_operations.rs @@ -2,6 +2,7 @@ use crate::constants::MYSQL_DS; #[cfg(feature = "mssql")] use crate::constants::SQL_SERVER_DS; + use canyon_sql::query::operators::LikeMysql; ///! Tests for the QueryBuilder available operations within Canyon. /// diff --git a/tests/crud/update_operations.rs b/tests/crud/update_operations.rs index 6dd4c223..5b6f5146 100644 --- a/tests/crud/update_operations.rs +++ b/tests/crud/update_operations.rs @@ -1,11 +1,10 @@ ///! Integration tests for the CRUD operations available in `Canyon` that ///! generates and executes *UPDATE* statements use canyon_sql::crud::CrudOperations; +use crate::tests_models::league::*; #[cfg(feature = "mssql")] use crate::constants::SQL_SERVER_DS; -use crate::tests_models::league::*; - #[cfg(feature = "mysql")] use crate::constants::MYSQL_DS; From 7245b75c4bcf9c8923ea3839c50e88e7256f9f81 Mon Sep 17 00:00:00 2001 From: onsystem Date: Tue, 19 Sep 2023 23:54:50 +0200 Subject: [PATCH 14/27] mysql-support remove comment to mysql implementation in canyon_database_connector.rs --- canyon_connection/src/canyon_database_connector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/canyon_connection/src/canyon_database_connector.rs b/canyon_connection/src/canyon_database_connector.rs index 6b2b783d..975f1c47 100644 --- a/canyon_connection/src/canyon_database_connector.rs +++ b/canyon_connection/src/canyon_database_connector.rs @@ -41,7 +41,7 @@ pub struct SqlServerConnection { /// A connection with a `Mysql` database #[cfg(feature = "mysql")] pub struct MysqlConnection { - pub client: Pool, //TODO this is Connection with server but it could be interesting to use Pool + pub client: Pool, } /// The Canyon database connection handler. When the client's program From 8b3ecd614fc92cf076defa1442e9c40040a3da14 Mon Sep 17 00:00:00 2001 From: onsystem Date: Tue, 19 Sep 2023 23:56:20 +0200 Subject: [PATCH 15/27] mysql-support canyon_macro.rs added in feature migrations --- canyon_macros/src/canyon_macro.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/canyon_macros/src/canyon_macro.rs b/canyon_macros/src/canyon_macro.rs index 48c89fcc..5b46962b 100644 --- a/canyon_macros/src/canyon_macro.rs +++ b/canyon_macros/src/canyon_macro.rs @@ -1,5 +1,5 @@ //! Provides helpers to build the `#[canyon_macros::canyon]` procedural like attribute macro - +#[cfg(feature = "migrations")] use canyon_connection::CANYON_TOKIO_RUNTIME; use canyon_migrations::migrations::handler::Migrations; use canyon_migrations::{CM_QUERIES_TO_EXECUTE, QUERIES_TO_EXECUTE}; From 335fe0da2d11e219f792ff6bbfa7988288961c11 Mon Sep 17 00:00:00 2001 From: onsystem Date: Wed, 20 Sep 2023 22:51:01 +0200 Subject: [PATCH 16/27] mysql-support replace error with feature in canyon_macro and separate pattern in crud.rs --- canyon_crud/src/crud.rs | 74 ++++++++++++++++--------------- canyon_macros/src/canyon_macro.rs | 2 +- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 02db7830..2399289f 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -1,10 +1,9 @@ use std::fmt::Display; - use async_trait::async_trait; + +use canyon_connection::{CACHED_DATABASE_CONN, get_database_connection}; use canyon_connection::canyon_database_connector::DatabaseConnection; -use canyon_connection::lazy_static::lazy_static; -use canyon_connection::{get_database_connection, CACHED_DATABASE_CONN}; -use regex::Regex; + use crate::bounds::QueryParameter; use crate::mapper::RowMapper; @@ -13,12 +12,11 @@ use crate::query_elements::query_builder::{ }; use crate::rows::CanyonRows; -lazy_static! { - static ref REGEX_DETECT_PARAMS: Regex = - Regex::new(r"\$([\d])+").expect("Error building regex pattern to detect params"); - static ref REGEX_DETECT_QUOTE: Regex = //Temporal solution escape quotes - Regex::new(r#"\"|\\"#).expect("Error building regex pattern to detect quotes"); -} + +//TODO This regex require move to constants but i cant because it if cycle dependency +pub const DETECT_PARAMS_IN_QUERY: &str = r"\$([\d])+"; +pub const DETECT_QUOTE_IN_QUERY: &str = r#"\"|\\"#; + /// This traits defines and implements a query against a database given /// an statement `stmt` and the params to pass the to the client. /// @@ -34,9 +32,9 @@ pub trait Transaction { params: Z, datasource_name: &'a str, ) -> Result, Box<(dyn std::error::Error + Sync + Send + 'static)>> - where - S: AsRef + Display + Sync + Send + 'a, - Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, + where + S: AsRef + Display + Sync + Send + 'a, + Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, { let mut guarded_cache = CACHED_DATABASE_CONN.lock().await; let database_conn = get_database_connection(datasource_name, &mut guarded_cache); @@ -49,7 +47,7 @@ pub trait Transaction { stmt.to_string(), params.as_ref(), ) - .await + .await } #[cfg(feature = "mssql")] DatabaseConnection::SqlServer(_) => { @@ -58,7 +56,7 @@ pub trait Transaction { &mut stmt.to_string(), params, ) - .await + .await } #[cfg(feature = "mysql")] DatabaseConnection::MySQL(_) => { @@ -86,8 +84,8 @@ pub trait Transaction { /// in the *canyon_sql_root::canyon_macros* crates, on the root of this project. #[async_trait] pub trait CrudOperations: Transaction -where - T: CrudOperations + RowMapper, + where + T: CrudOperations + RowMapper, { async fn find_all<'a>() -> Result, Box<(dyn std::error::Error + Send + Sync + 'static)>>; @@ -159,9 +157,10 @@ where #[cfg(feature = "postgres")] mod postgres_query_launcher { + use canyon_connection::canyon_database_connector::DatabaseConnection; + use crate::bounds::QueryParameter; use crate::rows::CanyonRows; - use canyon_connection::canyon_database_connector::DatabaseConnection; pub async fn launch<'a, T>( db_conn: &DatabaseConnection, @@ -185,19 +184,19 @@ mod postgres_query_launcher { #[cfg(feature = "mssql")] mod sqlserver_query_launcher { - use crate::rows::CanyonRows; use crate::{ bounds::QueryParameter, canyon_connection::{canyon_database_connector::DatabaseConnection, tiberius::Query}, }; + use crate::rows::CanyonRows; pub async fn launch<'a, T, Z>( db_conn: &mut DatabaseConnection, stmt: &mut String, params: Z, ) -> Result, Box<(dyn std::error::Error + Send + Sync + 'static)>> - where - Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, + where + Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, { // Re-generate de insert statement to adequate it to the SQL SERVER syntax to retrieve the PK value(s) after insert if stmt.contains("RETURNING") { @@ -233,22 +232,22 @@ mod sqlserver_query_launcher { #[cfg(feature = "mysql")] mod mysql_query_launcher { - use std::sync::Arc; - use canyon_connection::canyon_database_connector::DatabaseConnection; - use mysql_async::prelude::Query; use mysql_async::QueryWithParams; use mysql_async::Value; + use canyon_connection::canyon_database_connector::DatabaseConnection; + + use crate::bounds::QueryParameter; - use crate::crud::REGEX_DETECT_QUOTE; - use crate::rows::mysql::CanyonRowMysql; use crate::rows::CanyonRows; + use crate::rows::mysql::CanyonRowMysql; + use regex::Regex; + use crate::crud::{DETECT_PARAMS_IN_QUERY, DETECT_QUOTE_IN_QUERY}; use super::reorder_params; - use super::REGEX_DETECT_PARAMS; pub async fn launch<'a, T>( db_conn: &DatabaseConnection, @@ -258,9 +257,9 @@ mod mysql_query_launcher { let mysql_connection = db_conn.mysql_connection().client.get_conn().await?; let stmt_with_escape_characters = regex::escape(&stmt); - let query_string = REGEX_DETECT_PARAMS.replace_all(&stmt_with_escape_characters, "?"); + let query_string = Regex::new(DETECT_PARAMS_IN_QUERY)?.replace_all(&stmt_with_escape_characters, "?"); - let mut query_string = REGEX_DETECT_QUOTE + let mut query_string = Regex::new(DETECT_QUOTE_IN_QUERY)? .replace_all(&query_string, "") .to_string(); @@ -274,6 +273,7 @@ mod mysql_query_launcher { let params_query: Vec = reorder_params(&stmt, params, |f| f.as_mysql_param().to_value()); + //TODO let query_with_params = QueryWithParams { query: query_string, params: params_query, @@ -298,24 +298,26 @@ mod mysql_query_launcher { } } +//TODO can move fn reorder_params( stmt: &str, params: &[&'_ dyn QueryParameter<'_>], - fn_parser: impl Fn(&dyn QueryParameter<'_>) -> T, + fn_parser: impl Fn(&&dyn QueryParameter<'_>) -> T, ) -> Vec { let mut ordered_params = vec![]; + let rg = regex::Regex::new(DETECT_PARAMS_IN_QUERY) + .expect(format!("Error create regex with detect params pattern expression: {:?} ", DETECT_PARAMS_IN_QUERY).as_str()); - for positional_param in REGEX_DETECT_PARAMS.find_iter(stmt) { + for positional_param in rg.find_iter(stmt) { let pp: &str = positional_param.as_str(); - let pp_index = pp[1..] + let pp_index = pp[1..] // param $1 -> get 1 .parse::() - .expect("error parse mapped parameter to usized.") + .expect("Error parse mapped parameter to usized.") - 1; - let element = *params - .as_ref() + let element = params .get(pp_index) - .expect("error obtaining the element of the mapping against parameters."); + .expect("Error obtaining the element of the mapping against parameters."); ordered_params.push(fn_parser(element)); } diff --git a/canyon_macros/src/canyon_macro.rs b/canyon_macros/src/canyon_macro.rs index 5b46962b..48c89fcc 100644 --- a/canyon_macros/src/canyon_macro.rs +++ b/canyon_macros/src/canyon_macro.rs @@ -1,5 +1,5 @@ //! Provides helpers to build the `#[canyon_macros::canyon]` procedural like attribute macro -#[cfg(feature = "migrations")] + use canyon_connection::CANYON_TOKIO_RUNTIME; use canyon_migrations::migrations::handler::Migrations; use canyon_migrations::{CM_QUERIES_TO_EXECUTE, QUERIES_TO_EXECUTE}; From 2e9edb2528f09daadf7880cbb5883dca77b66820 Mon Sep 17 00:00:00 2001 From: onsystem Date: Tue, 10 Oct 2023 23:14:38 +0200 Subject: [PATCH 17/27] changes: remove CanyonRowsMysql and implement mysql_async, repair initialization mssql --- bash_aliases.sh | 0 canyon_crud/src/bounds.rs | 4 +- canyon_crud/src/crud.rs | 14 ++-- canyon_crud/src/mapper.rs | 4 +- canyon_crud/src/rows.rs | 81 +------------------- canyon_macros/src/lib.rs | 5 +- canyon_macros/src/query_operations/insert.rs | 8 +- 7 files changed, 21 insertions(+), 95 deletions(-) mode change 100644 => 100755 bash_aliases.sh diff --git a/bash_aliases.sh b/bash_aliases.sh old mode 100644 new mode 100755 diff --git a/canyon_crud/src/bounds.rs b/canyon_crud/src/bounds.rs index 91c869b1..27ffb97f 100644 --- a/canyon_crud/src/bounds.rs +++ b/canyon_crud/src/bounds.rs @@ -4,8 +4,6 @@ use crate::{ }; #[cfg(feature = "mysql")] use canyon_connection::mysql_async::{self, prelude::ToValue}; -#[cfg(feature = "mysql")] -use crate::rows::mysql::CanyonRowMysql; #[cfg(feature = "mssql")] use canyon_connection::tiberius::{self, ColumnData, IntoSql}; #[cfg(feature = "postgres")] @@ -104,7 +102,7 @@ impl Row for tiberius::Row { } #[cfg(feature = "mysql")] -impl Row for CanyonRowMysql { +impl Row for mysql_async::Row { fn as_any(&self) -> &dyn Any { self } diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 2399289f..26a158a9 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -243,7 +243,8 @@ mod mysql_query_launcher { use crate::bounds::QueryParameter; use crate::rows::CanyonRows; - use crate::rows::mysql::CanyonRowMysql; + use mysql_async::Row; + use mysql_common::row; use regex::Regex; use crate::crud::{DETECT_PARAMS_IN_QUERY, DETECT_QUOTE_IN_QUERY}; @@ -284,21 +285,24 @@ mod mysql_query_launcher { .await .expect("Error executing query in mysql"); + + let result_rows = if is_insert { - let last_insert = query_result.last_insert_id().map(Value::UInt); - vec![CanyonRowMysql::new(vec![last_insert], Arc::new([]))] + let last_insert = query_result.last_insert_id().map(Value::UInt).expect("Error getting pk id in insert"); + vec![row::new_row(vec![last_insert],Arc::new([]))] } else { - query_result - .map(CanyonRowMysql::from) + query_result.collect::() .await .expect("Error resolved trait FromRow in mysql") }; + Ok(CanyonRows::MySQL(result_rows)) } } //TODO can move +#[cfg(feature = "mysql")] fn reorder_params( stmt: &str, params: &[&'_ dyn QueryParameter<'_>], diff --git a/canyon_crud/src/mapper.rs b/canyon_crud/src/mapper.rs index 2d8b9e1d..252df1ce 100644 --- a/canyon_crud/src/mapper.rs +++ b/canyon_crud/src/mapper.rs @@ -1,5 +1,5 @@ #[cfg(feature = "mysql")] -use crate::rows::mysql::CanyonRowMysql; +use canyon_connection::mysql_async; #[cfg(feature = "mssql")] use canyon_connection::tiberius; #[cfg(feature = "postgres")] @@ -16,5 +16,5 @@ pub trait RowMapper>: Sized { #[cfg(feature = "mssql")] fn deserialize_sqlserver(row: &tiberius::Row) -> T; #[cfg(feature = "mysql")] - fn deserialize_mysql(row: &CanyonRowMysql) -> T; + fn deserialize_mysql(row: &mysql_async::Row) -> T; } diff --git a/canyon_crud/src/rows.rs b/canyon_crud/src/rows.rs index 23b0cd5d..517592a6 100644 --- a/canyon_crud/src/rows.rs +++ b/canyon_crud/src/rows.rs @@ -14,7 +14,7 @@ pub enum CanyonRows { #[cfg(feature = "mssql")] Tiberius(Vec), #[cfg(feature = "mysql")] - MySQL(Vec), + MySQL(Vec), UnusableTypeMarker(PhantomData), } @@ -37,7 +37,7 @@ impl CanyonRows { } #[cfg(feature = "mysql")] - pub fn get_mysql_rows(&self) -> &Vec { + pub fn get_mysql_rows(&self) -> &Vec { match self { Self::MySQL(v) => v, _ => panic!("This branch will never ever should be reachable"), @@ -86,80 +86,3 @@ impl CanyonRows { } } } - -#[cfg(feature = "mysql")] -pub mod mysql { - use mysql_async::{from_value, Column, Value}; - use mysql_common::{prelude::FromValue, row::ColumnIndex, Row}; - use std::{ops::Index, sync::Arc}; - - #[derive(Debug)] - pub struct CanyonRowMysql { - values: Vec>, - columns: Arc<[Column]>, - } - - impl CanyonRowMysql { - pub fn new(values: Vec>, columns: Arc<[Column]>) -> Self { - Self { values, columns } - } - - pub fn get(&self, index: I) -> Option - where - T: FromValue, - I: ColumnIndex, - { - index.idx(&self.columns).and_then(|idx| { - self.values - .get(idx) - .and_then(|x| x.as_ref()) - .map(|x| from_value::(x.clone())) - }) - } - pub fn get_by_index(&self, index: usize) -> Option - where - T: FromValue, - //I: ColumnIndex, - { - //TODO - self.values - .get(index) - .and_then(|x| x.as_ref()) - .map(|v| from_value::(v.clone())) - } - } - - impl From for CanyonRowMysql { - fn from(value: Row) -> Self { - Self { - values: value - .columns() - .iter() - .map(|c| value.get(c.name_str().as_ref())) //TODO - .collect(), - columns: value.columns(), - } - } - } - - impl Index for CanyonRowMysql { - type Output = Value; - - fn index(&self, index: usize) -> &Value { - self.values[index].as_ref().unwrap() - } - } - - impl<'a> Index<&'a str> for CanyonRowMysql { - type Output = Value; - - fn index<'r>(&'r self, index: &'a str) -> &'r Value { - for (i, column) in self.columns.iter().enumerate() { - if column.name_ref() == index.as_bytes() { - return self.values[i].as_ref().unwrap(); - } - } - panic!("No such column: `{}` in row {:?}", index, self); - } - } -} diff --git a/canyon_macros/src/lib.rs b/canyon_macros/src/lib.rs index 9549570f..a7902a2d 100755 --- a/canyon_macros/src/lib.rs +++ b/canyon_macros/src/lib.rs @@ -8,6 +8,7 @@ mod canyon_macro; mod query_operations; mod utils; + use canyon_entity_macro::parse_canyon_entity_proc_macro_attr; use proc_macro::TokenStream as CompilerTokenStream; use proc_macro2::{Ident, TokenStream}; @@ -558,7 +559,7 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac #(#init_field_values_sqlserver),* } } - fn deserialize_mysql(row: &canyon_crud::rows::mysql::CanyonRowMysql) -> #ty { + fn deserialize_mysql(row: &canyon_sql::db_clients::mysql_async::Row) -> #ty { Self { #(#init_field_values_mysql),* } @@ -588,7 +589,7 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac } else if mysql_enabled { quote! { impl canyon_sql::crud::RowMapper for #ty { - fn deserialize_mysql(row: &canyon_crud::rows::mysql::CanyonRowMysql) -> #ty { + fn deserialize_mysql(row: &canyon_sql::db_clients::mysql_async::Row) -> #ty { Self { #(#init_field_values_mysql),* } diff --git a/canyon_macros/src/query_operations/insert.rs b/canyon_macros/src/query_operations/insert.rs index 5c97f66c..94a4ac45 100644 --- a/canyon_macros/src/query_operations/insert.rs +++ b/canyon_macros/src/query_operations/insert.rs @@ -63,7 +63,7 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri self.#pk_ident = v .get(0) .ok_or("Failed getting the returned IDs for a multi insert")? - .get_by_index::<#pk_type>(0) + .get::<#pk_type,&str>(#primary_key) .ok_or("MYSQL primary key type failed to be set as value")?; Ok(()) } @@ -95,7 +95,7 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri self.#pk_ident = v .get(0) .ok_or("Failed getting the returned IDs for a multi insert")? - .get_by_index::<#pk_type>(0) + .get::<#pk_type,&str>(#primary_key) .ok_or("MYSQL primary key type failed to be set as value")?; Ok(()) } @@ -311,7 +311,7 @@ pub fn generate_multiple_insert_tokens( instance.#pk_ident = v .get(idx) .expect("Failed getting the returned IDs for a multi insert") - .get_by_index::<#pk_type>(0) + .get::<#pk_type,&str>(#pk) .expect("MYSQL primary key type failed to be set as value"); } Ok(()) @@ -351,7 +351,7 @@ pub fn generate_multiple_insert_tokens( instance.#pk_ident = v .get(idx) .expect("Failed getting the returned IDs for a multi insert") - .get_by_index::<#pk_type>(0) + .get::<#pk_type,&str>(#pk) .expect("MYSQL primary key type failed to be set as value"); } Ok(()) From 1715b18229123d8d87d5bb58a0a1d75b9314c830 Mon Sep 17 00:00:00 2001 From: onsystem Date: Tue, 10 Oct 2023 23:53:57 +0200 Subject: [PATCH 18/27] changes: corrections other test --- canyon_crud/src/crud.rs | 6 +++--- canyon_macros/src/query_operations/insert.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 26a158a9..bafd8d36 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -244,6 +244,7 @@ mod mysql_query_launcher { use crate::bounds::QueryParameter; use crate::rows::CanyonRows; use mysql_async::Row; + use mysql_common::constants::ColumnType; use mysql_common::row; use regex::Regex; @@ -286,17 +287,16 @@ mod mysql_query_launcher { .expect("Error executing query in mysql"); - let result_rows = if is_insert { let last_insert = query_result.last_insert_id().map(Value::UInt).expect("Error getting pk id in insert"); - vec![row::new_row(vec![last_insert],Arc::new([]))] + + vec![row::new_row(vec![last_insert], Arc::new([mysql_async::Column::new(ColumnType::MYSQL_TYPE_UNKNOWN)]))] } else { query_result.collect::() .await .expect("Error resolved trait FromRow in mysql") }; - Ok(CanyonRows::MySQL(result_rows)) } } diff --git a/canyon_macros/src/query_operations/insert.rs b/canyon_macros/src/query_operations/insert.rs index 94a4ac45..bb3c76ff 100644 --- a/canyon_macros/src/query_operations/insert.rs +++ b/canyon_macros/src/query_operations/insert.rs @@ -63,7 +63,7 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri self.#pk_ident = v .get(0) .ok_or("Failed getting the returned IDs for a multi insert")? - .get::<#pk_type,&str>(#primary_key) + .get::<#pk_type,usize>(0) .ok_or("MYSQL primary key type failed to be set as value")?; Ok(()) } @@ -95,7 +95,7 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri self.#pk_ident = v .get(0) .ok_or("Failed getting the returned IDs for a multi insert")? - .get::<#pk_type,&str>(#primary_key) + .get::<#pk_type,usize>(0) .ok_or("MYSQL primary key type failed to be set as value")?; Ok(()) } @@ -311,7 +311,7 @@ pub fn generate_multiple_insert_tokens( instance.#pk_ident = v .get(idx) .expect("Failed getting the returned IDs for a multi insert") - .get::<#pk_type,&str>(#pk) + .get::<#pk_type,usize>(0) .expect("MYSQL primary key type failed to be set as value"); } Ok(()) @@ -351,7 +351,7 @@ pub fn generate_multiple_insert_tokens( instance.#pk_ident = v .get(idx) .expect("Failed getting the returned IDs for a multi insert") - .get::<#pk_type,&str>(#pk) + .get::<#pk_type,usize>(0) .expect("MYSQL primary key type failed to be set as value"); } Ok(()) From 0871b407187f143cdce652c1f3215e611d30a0bc Mon Sep 17 00:00:00 2001 From: onsystem Date: Thu, 12 Oct 2023 01:46:37 +0200 Subject: [PATCH 19/27] changes: insert and multiinsert match_rows --- canyon_crud/src/crud.rs | 4 +- canyon_macros/src/query_operations/insert.rs | 216 +++++-------------- 2 files changed, 58 insertions(+), 162 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index bafd8d36..a92c8127 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -266,7 +266,6 @@ mod mysql_query_launcher { .to_string(); let mut is_insert = false; - //In mysql isn`t support RETURNING clause in insert operation if let Some(index_start_clausule_returning) = query_string.find(" RETURNING") { query_string.truncate(index_start_clausule_returning); is_insert = true; @@ -275,7 +274,6 @@ mod mysql_query_launcher { let params_query: Vec = reorder_params(&stmt, params, |f| f.as_mysql_param().to_value()); - //TODO let query_with_params = QueryWithParams { query: query_string, params: params_query, @@ -301,7 +299,7 @@ mod mysql_query_launcher { } } -//TODO can move + #[cfg(feature = "mysql")] fn reorder_params( stmt: &str, diff --git a/canyon_macros/src/query_operations/insert.rs b/canyon_macros/src/query_operations/insert.rs index bb3c76ff..c6e5e205 100644 --- a/canyon_macros/src/query_operations/insert.rs +++ b/canyon_macros/src/query_operations/insert.rs @@ -38,48 +38,33 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri let pk_ident = &pk_data.0; let pk_type = &pk_data.1; - let postgres_enabled = cfg!(feature = "postgres"); - let mssql_enabled = cfg!(feature = "mssql"); - let mysql_enabled = cfg!(feature = "mysql"); + quote! { + #remove_pk_value_from_fn_entry; - let match_rows = if postgres_enabled && mssql_enabled && mysql_enabled { - quote! { - canyon_sql::crud::CanyonRows::Postgres(mut v) => { - self.#pk_ident = v - .get(0) - .ok_or("Failed getting the returned IDs for an insert")? - .get::<&str, #pk_type>(#primary_key); - Ok(()) - } - canyon_sql::crud::CanyonRows::Tiberius(mut v) => { - self.#pk_ident = v - .get(0) - .ok_or("Failed getting the returned IDs for a multi insert")? - .get::<#pk_type, &str>(#primary_key) - .ok_or("SQL Server primary key type failed to be set as value")?; - Ok(()) - } - canyon_sql::crud::CanyonRows::MySQL(mut v) => { - self.#pk_ident = v - .get(0) - .ok_or("Failed getting the returned IDs for a multi insert")? - .get::<#pk_type,usize>(0) - .ok_or("MYSQL primary key type failed to be set as value")?; - Ok(()) - } - } - } else if postgres_enabled { - quote! { + let stmt = format!( + "INSERT INTO {} ({}) VALUES ({}) RETURNING {}", + #table_schema_data, + #insert_columns, + #placeholders, + #primary_key + ); + + let rows = <#ty as canyon_sql::crud::Transaction<#ty>>::query( + stmt, + values, + datasource_name + ).await?; + + match rows { + #[cfg(feature = "postgres")] canyon_sql::crud::CanyonRows::Postgres(mut v) => { self.#pk_ident = v .get(0) .ok_or("Failed getting the returned IDs for an insert")? .get::<&str, #pk_type>(#primary_key); Ok(()) - } - } - } else if mssql_enabled { - quote! { + }, + #[cfg(feature = "mssql")] canyon_sql::crud::CanyonRows::Tiberius(mut v) => { self.#pk_ident = v .get(0) @@ -87,10 +72,8 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri .get::<#pk_type, &str>(#primary_key) .ok_or("SQL Server primary key type failed to be set as value")?; Ok(()) - } - } - } else if mysql_enabled { - quote! { + }, + #[cfg(feature = "mysql")] canyon_sql::crud::CanyonRows::MySQL(mut v) => { self.#pk_ident = v .get(0) @@ -98,37 +81,7 @@ pub fn generate_insert_tokens(macro_data: &MacroTokens, table_schema_data: &Stri .get::<#pk_type,usize>(0) .ok_or("MYSQL primary key type failed to be set as value")?; Ok(()) - } - } - } else { - quote! { - panic!( - "Reached a branch in the implementation of the Row Mapper macro that should never be reached.\ - This is a severe bug of Canyon-SQL. Please, open us an issue at \ - https://github.com/zerodaycode/Canyon-SQL/issues and let us know about that failure." - ) - } - }; - - quote! { - #remove_pk_value_from_fn_entry; - - let stmt = format!( - "INSERT INTO {} ({}) VALUES ({}) RETURNING {}", - #table_schema_data, - #insert_columns, - #placeholders, - #primary_key - ); - - let rows = <#ty as canyon_sql::crud::Transaction<#ty>>::query( - stmt, - values, - datasource_name - ).await?; - - match rows { - #match_rows + }, _ => panic!("Reached the panic match arm of insert for the DatabaseConnection type") // TODO remove when the generics will be refactored } } @@ -279,94 +232,6 @@ pub fn generate_multiple_insert_tokens( let pk_ident = &pk_data.0; let pk_type = &pk_data.1; - let postgres_enabled = cfg!(feature = "postgres"); - let mssql_enabled = cfg!(feature = "mssql"); - let mysql_enabled = cfg!(feature = "mysql"); - - let match_multi_insert_rows = if postgres_enabled && mssql_enabled && mysql_enabled { - quote! { - canyon_sql::crud::CanyonRows::Postgres(mut v) => { - for (idx, instance) in instances.iter_mut().enumerate() { - instance.#pk_ident = v - .get(idx) - .expect("Failed getting the returned IDs for a multi insert") - .get::<&str, #pk_type>(#pk); - } - - Ok(()) - } - canyon_sql::crud::CanyonRows::Tiberius(mut v) => { - for (idx, instance) in instances.iter_mut().enumerate() { - instance.#pk_ident = v - .get(idx) - .expect("Failed getting the returned IDs for a multi insert") - .get::<#pk_type, &str>(#pk) - .expect("SQL Server primary key type failed to be set as value"); - } - - Ok(()) - } - canyon_sql::crud::CanyonRows::MySQL(mut v) => { - for (idx, instance) in instances.iter_mut().enumerate() { - instance.#pk_ident = v - .get(idx) - .expect("Failed getting the returned IDs for a multi insert") - .get::<#pk_type,usize>(0) - .expect("MYSQL primary key type failed to be set as value"); - } - Ok(()) - } - } - } else if postgres_enabled { - quote! { - canyon_sql::crud::CanyonRows::Postgres(mut v) => { - for (idx, instance) in instances.iter_mut().enumerate() { - instance.#pk_ident = v - .get(idx) - .expect("Failed getting the returned IDs for a multi insert") - .get::<&str, #pk_type>(#pk); - } - - Ok(()) - } - } - } else if mssql_enabled { - quote! { - canyon_sql::crud::CanyonRows::Tiberius(mut v) => { - for (idx, instance) in instances.iter_mut().enumerate() { - instance.#pk_ident = v - .get(idx) - .expect("Failed getting the returned IDs for a multi insert") - .get::<#pk_type, &str>(#pk) - .expect("SQL Server primary key type failed to be set as value"); - } - - Ok(()) - } - } - } else if mysql_enabled { - quote! { - canyon_sql::crud::CanyonRows::MySQL(mut v) => { - for (idx, instance) in instances.iter_mut().enumerate() { - instance.#pk_ident = v - .get(idx) - .expect("Failed getting the returned IDs for a multi insert") - .get::<#pk_type,usize>(0) - .expect("MYSQL primary key type failed to be set as value"); - } - Ok(()) - } - } - } else { - quote! { - panic!( - "Reached a branch in the implementation of the Row Mapper macro that should never be reached.\ - This is a severe bug of Canyon-SQL. Please, open us an issue at \ - https://github.com/zerodaycode/Canyon-SQL/issues and let us know about that failure." - ) - } - }; - quote! { mapped_fields = #column_names .split(", ") @@ -436,7 +301,40 @@ pub fn generate_multiple_insert_tokens( ).await?; match multi_insert_result { - #match_multi_insert_rows + #[cfg(feature="postgres")] + canyon_sql::crud::CanyonRows::Postgres(mut v) => { + for (idx, instance) in instances.iter_mut().enumerate() { + instance.#pk_ident = v + .get(idx) + .expect("Failed getting the returned IDs for a multi insert") + .get::<&str, #pk_type>(#pk); + } + + Ok(()) + }, + #[cfg(feature="mssql")] + canyon_sql::crud::CanyonRows::Tiberius(mut v) => { + for (idx, instance) in instances.iter_mut().enumerate() { + instance.#pk_ident = v + .get(idx) + .expect("Failed getting the returned IDs for a multi insert") + .get::<#pk_type, &str>(#pk) + .expect("SQL Server primary key type failed to be set as value"); + } + + Ok(()) + }, + #[cfg(feature="mysql")] + canyon_sql::crud::CanyonRows::MySQL(mut v) => { + for (idx, instance) in instances.iter_mut().enumerate() { + instance.#pk_ident = v + .get(idx) + .expect("Failed getting the returned IDs for a multi insert") + .get::<#pk_type,usize>(0) + .expect("MYSQL primary key type failed to be set as value"); + } + Ok(()) + }, _ => panic!() // TODO remove when the generics will be refactored } } From 625672aeab5b9918c0c44d8dd3b33424d6d27240 Mon Sep 17 00:00:00 2001 From: onsystem Date: Thu, 12 Oct 2023 02:40:58 +0200 Subject: [PATCH 20/27] changes: lib cargo_macros RowMapper --- canyon_crud/src/crud.rs | 60 ++++++++++++++++------------ canyon_macros/src/lib.rs | 70 +++++++-------------------------- tests/crud/update_operations.rs | 6 +-- 3 files changed, 51 insertions(+), 85 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index a92c8127..12c3a642 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -1,9 +1,8 @@ -use std::fmt::Display; use async_trait::async_trait; +use std::fmt::Display; -use canyon_connection::{CACHED_DATABASE_CONN, get_database_connection}; use canyon_connection::canyon_database_connector::DatabaseConnection; - +use canyon_connection::{get_database_connection, CACHED_DATABASE_CONN}; use crate::bounds::QueryParameter; use crate::mapper::RowMapper; @@ -12,7 +11,6 @@ use crate::query_elements::query_builder::{ }; use crate::rows::CanyonRows; - //TODO This regex require move to constants but i cant because it if cycle dependency pub const DETECT_PARAMS_IN_QUERY: &str = r"\$([\d])+"; pub const DETECT_QUOTE_IN_QUERY: &str = r#"\"|\\"#; @@ -32,9 +30,9 @@ pub trait Transaction { params: Z, datasource_name: &'a str, ) -> Result, Box<(dyn std::error::Error + Sync + Send + 'static)>> - where - S: AsRef + Display + Sync + Send + 'a, - Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, + where + S: AsRef + Display + Sync + Send + 'a, + Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, { let mut guarded_cache = CACHED_DATABASE_CONN.lock().await; let database_conn = get_database_connection(datasource_name, &mut guarded_cache); @@ -47,7 +45,7 @@ pub trait Transaction { stmt.to_string(), params.as_ref(), ) - .await + .await } #[cfg(feature = "mssql")] DatabaseConnection::SqlServer(_) => { @@ -56,7 +54,7 @@ pub trait Transaction { &mut stmt.to_string(), params, ) - .await + .await } #[cfg(feature = "mysql")] DatabaseConnection::MySQL(_) => { @@ -84,8 +82,8 @@ pub trait Transaction { /// in the *canyon_sql_root::canyon_macros* crates, on the root of this project. #[async_trait] pub trait CrudOperations: Transaction - where - T: CrudOperations + RowMapper, +where + T: CrudOperations + RowMapper, { async fn find_all<'a>() -> Result, Box<(dyn std::error::Error + Send + Sync + 'static)>>; @@ -184,19 +182,19 @@ mod postgres_query_launcher { #[cfg(feature = "mssql")] mod sqlserver_query_launcher { + use crate::rows::CanyonRows; use crate::{ bounds::QueryParameter, canyon_connection::{canyon_database_connector::DatabaseConnection, tiberius::Query}, }; - use crate::rows::CanyonRows; pub async fn launch<'a, T, Z>( db_conn: &mut DatabaseConnection, stmt: &mut String, params: Z, ) -> Result, Box<(dyn std::error::Error + Send + Sync + 'static)>> - where - Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, + where + Z: AsRef<[&'a dyn QueryParameter<'a>]> + Sync + Send + 'a, { // Re-generate de insert statement to adequate it to the SQL SERVER syntax to retrieve the PK value(s) after insert if stmt.contains("RETURNING") { @@ -240,16 +238,15 @@ mod mysql_query_launcher { use canyon_connection::canyon_database_connector::DatabaseConnection; - use crate::bounds::QueryParameter; use crate::rows::CanyonRows; use mysql_async::Row; use mysql_common::constants::ColumnType; use mysql_common::row; - use regex::Regex; - use crate::crud::{DETECT_PARAMS_IN_QUERY, DETECT_QUOTE_IN_QUERY}; use super::reorder_params; + use crate::crud::{DETECT_PARAMS_IN_QUERY, DETECT_QUOTE_IN_QUERY}; + use regex::Regex; pub async fn launch<'a, T>( db_conn: &DatabaseConnection, @@ -259,7 +256,8 @@ mod mysql_query_launcher { let mysql_connection = db_conn.mysql_connection().client.get_conn().await?; let stmt_with_escape_characters = regex::escape(&stmt); - let query_string = Regex::new(DETECT_PARAMS_IN_QUERY)?.replace_all(&stmt_with_escape_characters, "?"); + let query_string = + Regex::new(DETECT_PARAMS_IN_QUERY)?.replace_all(&stmt_with_escape_characters, "?"); let mut query_string = Regex::new(DETECT_QUOTE_IN_QUERY)? .replace_all(&query_string, "") @@ -284,13 +282,19 @@ mod mysql_query_launcher { .await .expect("Error executing query in mysql"); - let result_rows = if is_insert { - let last_insert = query_result.last_insert_id().map(Value::UInt).expect("Error getting pk id in insert"); - - vec![row::new_row(vec![last_insert], Arc::new([mysql_async::Column::new(ColumnType::MYSQL_TYPE_UNKNOWN)]))] + let last_insert = query_result + .last_insert_id() + .map(Value::UInt) + .expect("Error getting pk id in insert"); + + vec![row::new_row( + vec![last_insert], + Arc::new([mysql_async::Column::new(ColumnType::MYSQL_TYPE_UNKNOWN)]), + )] } else { - query_result.collect::() + query_result + .collect::() .await .expect("Error resolved trait FromRow in mysql") }; @@ -299,7 +303,6 @@ mod mysql_query_launcher { } } - #[cfg(feature = "mysql")] fn reorder_params( stmt: &str, @@ -307,8 +310,13 @@ fn reorder_params( fn_parser: impl Fn(&&dyn QueryParameter<'_>) -> T, ) -> Vec { let mut ordered_params = vec![]; - let rg = regex::Regex::new(DETECT_PARAMS_IN_QUERY) - .expect(format!("Error create regex with detect params pattern expression: {:?} ", DETECT_PARAMS_IN_QUERY).as_str()); + let rg = regex::Regex::new(DETECT_PARAMS_IN_QUERY).expect( + format!( + "Error create regex with detect params pattern expression: {:?} ", + DETECT_PARAMS_IN_QUERY + ) + .as_str(), + ); for positional_param in rg.find_iter(stmt) { let pp: &str = positional_param.as_str(); diff --git a/canyon_macros/src/lib.rs b/canyon_macros/src/lib.rs index a7902a2d..6f094fff 100755 --- a/canyon_macros/src/lib.rs +++ b/canyon_macros/src/lib.rs @@ -8,7 +8,6 @@ mod canyon_macro; mod query_operations; mod utils; - use canyon_entity_macro::parse_canyon_entity_proc_macro_attr; use proc_macro::TokenStream as CompilerTokenStream; use proc_macro2::{Ident, TokenStream}; @@ -542,68 +541,27 @@ pub fn implement_row_mapper_for_type(input: proc_macro::TokenStream) -> proc_mac // The type of the Struct let ty = ast.ident; - let postgres_enabled = cfg!(feature = "postgres"); - let mssql_enabled = cfg!(feature = "mssql"); - let mysql_enabled = cfg!(feature = "mysql"); - - let tokens = if postgres_enabled && mssql_enabled && mysql_enabled { - quote! { - impl canyon_sql::crud::RowMapper for #ty { - fn deserialize_postgresql(row: &canyon_sql::db_clients::tokio_postgres::Row) -> #ty { - Self { - #(#init_field_values),* - } - } - fn deserialize_sqlserver(row: &canyon_sql::db_clients::tiberius::Row) -> #ty { - Self { - #(#init_field_values_sqlserver),* - } - } - fn deserialize_mysql(row: &canyon_sql::db_clients::mysql_async::Row) -> #ty { - Self { - #(#init_field_values_mysql),* - } - } - } - } - } else if postgres_enabled { - quote! { - impl canyon_sql::crud::RowMapper for #ty { - fn deserialize_postgresql(row: &canyon_sql::db_clients::tokio_postgres::Row) -> #ty { - Self { - #(#init_field_values),* - } + let tokens = quote! { + impl canyon_sql::crud::RowMapper for #ty { + #[cfg(feature="postgres")] + fn deserialize_postgresql(row: &canyon_sql::db_clients::tokio_postgres::Row) -> #ty { + Self { + #(#init_field_values),* } } - } - } else if mssql_enabled { - quote! { - impl canyon_sql::crud::RowMapper for #ty { - fn deserialize_sqlserver(row: &canyon_sql::db_clients::tiberius::Row) -> #ty { - Self { - #(#init_field_values_sqlserver),* - } + #[cfg(feature="mssql")] + fn deserialize_sqlserver(row: &canyon_sql::db_clients::tiberius::Row) -> #ty { + Self { + #(#init_field_values_sqlserver),* } } - } - } else if mysql_enabled { - quote! { - impl canyon_sql::crud::RowMapper for #ty { - fn deserialize_mysql(row: &canyon_sql::db_clients::mysql_async::Row) -> #ty { - Self { - #(#init_field_values_mysql),* - } + #[cfg(feature="mysql")] + fn deserialize_mysql(row: &canyon_sql::db_clients::mysql_async::Row) -> #ty { + Self { + #(#init_field_values_mysql),* } } } - } else { - quote! { - panic!( - "Reached a branch in the implementation of the Row Mapper macro that should never be reached.\ - This is a severe bug of Canyon-SQL. Please, open us an issue at \ - https://github.com/zerodaycode/Canyon-SQL/issues and let us know about that failure." - ) - } }; tokens.into() diff --git a/tests/crud/update_operations.rs b/tests/crud/update_operations.rs index 5b6f5146..18283cb7 100644 --- a/tests/crud/update_operations.rs +++ b/tests/crud/update_operations.rs @@ -1,12 +1,12 @@ +use crate::tests_models::league::*; ///! Integration tests for the CRUD operations available in `Canyon` that ///! generates and executes *UPDATE* statements use canyon_sql::crud::CrudOperations; -use crate::tests_models::league::*; -#[cfg(feature = "mssql")] -use crate::constants::SQL_SERVER_DS; #[cfg(feature = "mysql")] use crate::constants::MYSQL_DS; +#[cfg(feature = "mssql")] +use crate::constants::SQL_SERVER_DS; /// Update operation is a *CRUD* method defined for some entity `T`, that works by appliying /// some change to a Rust's entity instance, and persisting them into the database. From 195bd77aa44f1547319eaec8f417cd34b978bce2 Mon Sep 17 00:00:00 2001 From: onsystem Date: Thu, 12 Oct 2023 18:08:03 +0200 Subject: [PATCH 21/27] changes: select macro remove else if to generate tokenstream with action count --- canyon_crud/src/crud.rs | 3 +- canyon_macros/src/query_operations/select.rs | 51 +++----------------- 2 files changed, 10 insertions(+), 44 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 12c3a642..bc3c8ec0 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -11,8 +11,9 @@ use crate::query_elements::query_builder::{ }; use crate::rows::CanyonRows; -//TODO This regex require move to constants but i cant because it if cycle dependency +#[cfg(feature = "mysql")] pub const DETECT_PARAMS_IN_QUERY: &str = r"\$([\d])+"; +#[cfg(feature = "mysql")] pub const DETECT_QUOTE_IN_QUERY: &str = r#"\"|\\"#; /// This traits defines and implements a query against a database given diff --git a/canyon_macros/src/query_operations/select.rs b/canyon_macros/src/query_operations/select.rs index 3556d42c..82a1a5b5 100644 --- a/canyon_macros/src/query_operations/select.rs +++ b/canyon_macros/src/query_operations/select.rs @@ -150,58 +150,23 @@ pub fn generate_count_tokens( let ty_str = &ty.to_string(); let stmt = format!("SELECT COUNT(*) FROM {table_schema_data}"); - let postgres_enabled = cfg!(feature = "postgres"); - let mssql_enabled = cfg!(feature = "mssql"); - let mysql_enabled = cfg!(feature = "mysql"); - - let result_handling = if postgres_enabled && mssql_enabled && mysql_enabled { - quote! { - canyon_sql::crud::CanyonRows::Postgres(mut v) => Ok( + let result_handling = quote! { + #[cfg(feature="postgres")] + canyon_sql::crud::CanyonRows::Postgres(mut v) => Ok( v.remove(0).get::<&str, i64>("count") ), - canyon_sql::crud::CanyonRows::Tiberius(mut v) => + #[cfg(feature="mssql")] + canyon_sql::crud::CanyonRows::Tiberius(mut v) => v.remove(0) .get::(0) .map(|c| c as i64) .ok_or(format!("Failure in the COUNT query for MSSQL for: {}", #ty_str).into()) .into(), - canyon_sql::crud::CanyonRows::MySQL(mut v) => v.remove(0) + #[cfg(feature="mysql")] + canyon_sql::crud::CanyonRows::MySQL(mut v) => v.remove(0) .get::(0) .ok_or(format!("Failure in the COUNT query for MYSQL for: {}", #ty_str).into()), _ => panic!() // TODO remove when the generics will be refactored - } - } else if postgres_enabled { - quote! { - canyon_sql::crud::CanyonRows::Postgres(mut v) => Ok( - v.remove(0).get::<&str, i64>("count") - ), - _ => panic!() // TODO remove when the generics will be refactored - } - } else if mssql_enabled { - quote! { - canyon_sql::crud::CanyonRows::Tiberius(mut v) => - v.remove(0) - .get::(0) - .map(|c| c as i64) - .ok_or(format!("Failure in the COUNT query for MSSQL for: {}", #ty_str).into()) - .into(), - _ => panic!() // TODO remove when the generics will be refactored - } - } else if mysql_enabled { - quote! { - canyon_sql::crud::CanyonRows::MySQL(mut v) => v.remove(0) - .get::(0) - .ok_or(format!("Failure result empty in the COUNT query for MYSQL for: {}", #ty_str).into()), - _ => panic!() - } - } else { - quote! { - panic!( - "Reached a branch in the implementation of the Row Mapper macro that should never be reached.\ - This is a severe bug of Canyon-SQL. Please, open us an issue at \ - https://github.com/zerodaycode/Canyon-SQL/issues and let us know about that failure." - ) - } }; quote! { @@ -391,7 +356,7 @@ pub fn generate_find_by_foreign_key_tokens( }; fk_quotes.push(( - quote!{ #quoted_method_signature; }, + quote! { #quoted_method_signature; }, quote! { /// Searches the parent entity (if exists) for this type #quoted_method_signature { From 76473736a8e2582895a1a168dbd0c40e2ec92044 Mon Sep 17 00:00:00 2001 From: onsystem Date: Sat, 14 Oct 2023 17:55:00 +0200 Subject: [PATCH 22/27] changes: resolve clippy error format! in expect to create Regex --- canyon_crud/src/crud.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index bc3c8ec0..85c4a4c6 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -312,11 +312,10 @@ fn reorder_params( ) -> Vec { let mut ordered_params = vec![]; let rg = regex::Regex::new(DETECT_PARAMS_IN_QUERY).expect( - format!( + &format!( "Error create regex with detect params pattern expression: {:?} ", DETECT_PARAMS_IN_QUERY - ) - .as_str(), + ), ); for positional_param in rg.find_iter(stmt) { From 8631628e38f01134fc90c77c933f486a1c08e4ef Mon Sep 17 00:00:00 2001 From: onsystem Date: Sat, 14 Oct 2023 18:08:34 +0200 Subject: [PATCH 23/27] changes: resolve clippy error format! in expect to create Regex --- canyon_crud/src/crud.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 85c4a4c6..55ba7ae6 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -311,12 +311,7 @@ fn reorder_params( fn_parser: impl Fn(&&dyn QueryParameter<'_>) -> T, ) -> Vec { let mut ordered_params = vec![]; - let rg = regex::Regex::new(DETECT_PARAMS_IN_QUERY).expect( - &format!( - "Error create regex with detect params pattern expression: {:?} ", - DETECT_PARAMS_IN_QUERY - ), - ); + let rg = regex::Regex::new(DETECT_PARAMS_IN_QUERY).expect("Error create regex with detect params pattern expression"); for positional_param in rg.find_iter(stmt) { let pp: &str = positional_param.as_str(); From 144e9df00a2b402522fc996abe6494629cd82ca2 Mon Sep 17 00:00:00 2001 From: onsystem Date: Fri, 20 Oct 2023 00:32:47 +0200 Subject: [PATCH 24/27] changes: implement Operator by datasource type --- .../src/canyon_database_connector.rs | 12 ++++- canyon_connection/src/lib.rs | 10 ++++ canyon_crud/src/query_elements/operators.rs | 50 ++++++++----------- .../src/query_elements/query_builder.rs | 23 +++++++-- tests/crud/querybuilder_operations.rs | 15 +++--- 5 files changed, 68 insertions(+), 42 deletions(-) diff --git a/canyon_connection/src/canyon_database_connector.rs b/canyon_connection/src/canyon_database_connector.rs index 975f1c47..438f3548 100644 --- a/canyon_connection/src/canyon_database_connector.rs +++ b/canyon_connection/src/canyon_database_connector.rs @@ -9,7 +9,7 @@ use tiberius::{AuthMethod, Config}; #[cfg(feature = "postgres")] use tokio_postgres::{Client, NoTls}; -use crate::datasources::DatasourceConfig; +use crate::datasources::{Auth, DatasourceConfig}; /// Represents the current supported databases by Canyon #[derive(Deserialize, Debug, Eq, PartialEq, Clone, Copy)] @@ -25,6 +25,16 @@ pub enum DatabaseType { MySQL, } +impl From<&Auth> for DatabaseType { + fn from(value: &Auth) -> Self { + match value { + crate::datasources::Auth::Postgres(_) => DatabaseType::PostgreSql, + crate::datasources::Auth::SqlServer(_) => DatabaseType::SqlServer, + crate::datasources::Auth::MySQL(_) => DatabaseType::MySQL, + } + } +} + /// A connection with a `PostgreSQL` database #[cfg(feature = "postgres")] pub struct PostgreSqlConnection { diff --git a/canyon_connection/src/lib.rs b/canyon_connection/src/lib.rs index 2723e201..140c030d 100644 --- a/canyon_connection/src/lib.rs +++ b/canyon_connection/src/lib.rs @@ -106,3 +106,13 @@ pub fn get_database_connection<'a>( ) } } + +pub fn get_database_config<'a>( + datasource_name: &str, + datasources_config: &'a [DatasourceConfig], +) -> &'a DatasourceConfig { + datasources_config + .iter() + .find(|dc| dc.name == datasource_name) + .unwrap_or_else(|| panic!("Not found datasource expected {datasource_name}")) +} diff --git a/canyon_crud/src/query_elements/operators.rs b/canyon_crud/src/query_elements/operators.rs index 44df931c..015ced03 100644 --- a/canyon_crud/src/query_elements/operators.rs +++ b/canyon_crud/src/query_elements/operators.rs @@ -1,5 +1,7 @@ +use canyon_connection::canyon_database_connector::DatabaseType; + pub trait Operator { - fn as_str(&self, placeholder_counter: usize) -> String; + fn as_str(&self, placeholder_counter: usize, datasource_type: &DatabaseType) -> String; } /// Enumerated type for represent the comparison operations @@ -20,7 +22,7 @@ pub enum Comp { } impl Operator for Comp { - fn as_str(&self, placeholder_counter: usize) -> String { + fn as_str(&self, placeholder_counter: usize, _datasource_type: &DatabaseType) -> String { match *self { Self::Eq => format!(" = ${placeholder_counter}"), Self::Neq => format!(" <> ${placeholder_counter}"), @@ -42,36 +44,26 @@ pub enum Like { } impl Operator for Like { - fn as_str(&self, placeholder_counter: usize) -> String { - match *self { - Like::Full => { - format!(" LIKE CONCAT('%', CAST(${placeholder_counter} AS VARCHAR) ,'%')") - } - Like::Left => format!(" LIKE CONCAT('%', CAST(${placeholder_counter} AS VARCHAR))"), - Like::Right => format!(" LIKE CONCAT(CAST(${placeholder_counter} AS VARCHAR) ,'%')"), - } - } -} - -#[cfg(feature = "mysql")] -pub enum LikeMysql { - /// Operator "LIKE" as '%pattern%' - Full, - /// Operator "LIKE" as '%pattern' - Left, - /// Operator "LIKE" as 'pattern%' - Right, -} + fn as_str(&self, placeholder_counter: usize, datasource_type: &DatabaseType) -> String { + let type_data_to_cast_str = match datasource_type { + #[cfg(feature = "postgres")] + DatabaseType::PostgreSql => "VARCHAR", + #[cfg(feature = "mssql")] + DatabaseType::SqlServer => "VARCHAR", + #[cfg(feature = "mysql")] + DatabaseType::MySQL => "CHAR", + }; -#[cfg(feature = "mysql")] -impl Operator for LikeMysql { - fn as_str(&self, placeholder_counter: usize) -> String { match *self { - LikeMysql::Full => { - format!(" LIKE CONCAT('%', CAST(${placeholder_counter} AS CHAR) ,'%')") + Like::Full => { + format!(" LIKE CONCAT('%', CAST(${placeholder_counter} AS {type_data_to_cast_str}) ,'%')") } - LikeMysql::Left => format!(" LIKE CONCAT('%', CAST(${placeholder_counter} AS CHAR))"), - LikeMysql::Right => format!(" LIKE CONCAT(CAST(${placeholder_counter} AS CHAR) ,'%')"), + Like::Left => format!( + " LIKE CONCAT('%', CAST(${placeholder_counter} AS {type_data_to_cast_str}))" + ), + Like::Right => format!( + " LIKE CONCAT(CAST(${placeholder_counter} AS {type_data_to_cast_str}) ,'%')" + ), } } } diff --git a/canyon_crud/src/query_elements/query_builder.rs b/canyon_crud/src/query_elements/query_builder.rs index e6987d47..6d00a51e 100644 --- a/canyon_crud/src/query_elements/query_builder.rs +++ b/canyon_crud/src/query_elements/query_builder.rs @@ -1,5 +1,9 @@ use std::fmt::Debug; +use canyon_connection::{ + canyon_database_connector::DatabaseType, get_database_config, DATASOURCES, +}; + use crate::{ bounds::{FieldIdentifier, FieldValueIdentifier, QueryParameter}, crud::{CrudOperations, Transaction}, @@ -138,6 +142,7 @@ where { query: Query<'a, T>, datasource_name: &'a str, + datasource_type: DatabaseType, } unsafe impl<'a, T> Send for QueryBuilder<'a, T> where @@ -158,6 +163,11 @@ where Self { query, datasource_name, + datasource_type: if datasource_name.is_empty() { + DatabaseType::PostgreSql + } else { + DatabaseType::from(&get_database_config(datasource_name, &DATASOURCES).auth) + }, } } @@ -180,8 +190,9 @@ where pub fn r#where>(&mut self, r#where: Z, op: impl Operator) { let (column_name, value) = r#where.value(); - let where_ = - String::from(" WHERE ") + column_name + &op.as_str(self.query.params.len() + 1); + let where_ = String::from(" WHERE ") + + column_name + + &op.as_str(self.query.params.len() + 1, &self.datasource_type); self.query.sql.push_str(&where_); self.query.params.push(value); @@ -190,7 +201,9 @@ where pub fn and>(&mut self, r#and: Z, op: impl Operator) { let (column_name, value) = r#and.value(); - let and_ = String::from(" AND ") + column_name + &op.as_str(self.query.params.len() + 1); + let and_ = String::from(" AND ") + + column_name + + &op.as_str(self.query.params.len() + 1, &self.datasource_type); self.query.sql.push_str(&and_); self.query.params.push(value); @@ -199,7 +212,9 @@ where pub fn or>(&mut self, r#and: Z, op: impl Operator) { let (column_name, value) = r#and.value(); - let and_ = String::from(" OR ") + column_name + &op.as_str(self.query.params.len() + 1); + let and_ = String::from(" OR ") + + column_name + + &op.as_str(self.query.params.len() + 1, &self.datasource_type); self.query.sql.push_str(&and_); self.query.params.push(value); diff --git a/tests/crud/querybuilder_operations.rs b/tests/crud/querybuilder_operations.rs index 8516d3e9..f4d03f38 100644 --- a/tests/crud/querybuilder_operations.rs +++ b/tests/crud/querybuilder_operations.rs @@ -3,7 +3,6 @@ use crate::constants::MYSQL_DS; #[cfg(feature = "mssql")] use crate::constants::SQL_SERVER_DS; -use canyon_sql::query::operators::LikeMysql; ///! Tests for the QueryBuilder available operations within Canyon. /// ///! QueryBuilder are the way of obtain more flexibility that with @@ -98,8 +97,8 @@ fn test_crud_find_with_querybuilder_and_fulllike_datasource_mssql() { #[canyon_sql::macros::canyon_tokio_test] fn test_crud_find_with_querybuilder_and_fulllike_datasource_mysql() { // Find all the leagues with "LC" in their name - let mut filtered_leagues_result = League::select_query_datasource(SQL_SERVER_DS); - filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), LikeMysql::Full); + let mut filtered_leagues_result = League::select_query_datasource(MYSQL_DS); + filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), Like::Full); assert_eq!( filtered_leagues_result.read_sql(), @@ -143,8 +142,8 @@ fn test_crud_find_with_querybuilder_and_leftlike_datasource_mssql() { #[canyon_sql::macros::canyon_tokio_test] fn test_crud_find_with_querybuilder_and_leftlike_datasource_mysql() { // Find all the leagues whose name ends with "CK" - let mut filtered_leagues_result = League::select_query(); - filtered_leagues_result.r#where(LeagueFieldValue::name(&"CK"), LikeMysql::Left); + let mut filtered_leagues_result = League::select_query_datasource(MYSQL_DS); + filtered_leagues_result.r#where(LeagueFieldValue::name(&"CK"), Like::Left); assert_eq!( filtered_leagues_result.read_sql(), @@ -187,8 +186,8 @@ fn test_crud_find_with_querybuilder_and_rightlike_datasource_mssql() { #[canyon_sql::macros::canyon_tokio_test] fn test_crud_find_with_querybuilder_and_rightlike_datasource_mysql() { // Find all the leagues whose name starts with "LC" - let mut filtered_leagues_result = League::select_query_datasource(SQL_SERVER_DS); - filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), LikeMysql::Right); + let mut filtered_leagues_result = League::select_query_datasource(MYSQL_DS); + filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), Like::Right); assert_eq!( filtered_leagues_result.read_sql(), @@ -214,7 +213,7 @@ fn test_crud_find_with_querybuilder_datasource_mssql() { #[canyon_sql::macros::canyon_tokio_test] fn test_crud_find_with_querybuilder_datasource_mysql() { // Find all the players where its ID column value is greater that 50 - let filtered_find_players = Player::select_query_datasource(SQL_SERVER_DS) + let filtered_find_players = Player::select_query_datasource(MYSQL_DS) .r#where(PlayerFieldValue::id(&50), Comp::Gt) .query() .await; From 9e4c91d5a84674c55f4792e0133c724d229d0094 Mon Sep 17 00:00:00 2001 From: onsystem Date: Sat, 21 Oct 2023 00:06:09 +0200 Subject: [PATCH 25/27] changes: added default datasources --- canyon_connection/src/lib.rs | 14 ++++++++++---- canyon_crud/src/query_elements/query_builder.rs | 8 +++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/canyon_connection/src/lib.rs b/canyon_connection/src/lib.rs index 140c030d..fd5d009e 100644 --- a/canyon_connection/src/lib.rs +++ b/canyon_connection/src/lib.rs @@ -111,8 +111,14 @@ pub fn get_database_config<'a>( datasource_name: &str, datasources_config: &'a [DatasourceConfig], ) -> &'a DatasourceConfig { - datasources_config - .iter() - .find(|dc| dc.name == datasource_name) - .unwrap_or_else(|| panic!("Not found datasource expected {datasource_name}")) + if datasource_name.is_empty() { + datasources_config + .get(0) + .unwrap_or_else(|| panic!("Not exist datasource")) + } else { + datasources_config + .iter() + .find(|dc| dc.name == datasource_name) + .unwrap_or_else(|| panic!("Not found datasource expected {datasource_name}")) + } } diff --git a/canyon_crud/src/query_elements/query_builder.rs b/canyon_crud/src/query_elements/query_builder.rs index 6d00a51e..e25ff9fe 100644 --- a/canyon_crud/src/query_elements/query_builder.rs +++ b/canyon_crud/src/query_elements/query_builder.rs @@ -163,11 +163,9 @@ where Self { query, datasource_name, - datasource_type: if datasource_name.is_empty() { - DatabaseType::PostgreSql - } else { - DatabaseType::from(&get_database_config(datasource_name, &DATASOURCES).auth) - }, + datasource_type: DatabaseType::from( + &get_database_config(datasource_name, &DATASOURCES).auth, + ), } } From c51a00e4234e6737cc635995ad04f451a8dcb3ba Mon Sep 17 00:00:00 2001 From: OnSystem Date: Sat, 2 Dec 2023 21:57:51 +0100 Subject: [PATCH 26/27] changes: correction error feature specify in datasources.rs enum Auth --- canyon_connection/src/datasources.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/canyon_connection/src/datasources.rs b/canyon_connection/src/datasources.rs index 1eba8fc7..ccfd3694 100644 --- a/canyon_connection/src/datasources.rs +++ b/canyon_connection/src/datasources.rs @@ -117,7 +117,7 @@ impl DatasourceConfig { Auth::Postgres(_) => DatabaseType::PostgreSql, #[cfg(feature = "mssql")] Auth::SqlServer(_) => DatabaseType::SqlServer, - #[cfg(feature = "postgres")] + #[cfg(feature = "mysql")] Auth::MySQL(_) => DatabaseType::MySQL, } } @@ -125,7 +125,7 @@ impl DatasourceConfig { #[derive(Deserialize, Debug, Clone, PartialEq)] pub enum Auth { - #[serde(alias = "PostgreSQL", alias = "postgresql", alias = "postgres")] + #[serde(alias = "PostgresSQL", alias = "postgresql", alias = "postgres")] #[cfg(feature = "postgres")] Postgres(PostgresAuth), #[serde(alias = "SqlServer", alias = "sqlserver", alias = "mssql")] From 5c09a3f1205f0c29d906e81c67873cd261e48cb4 Mon Sep 17 00:00:00 2001 From: OnSystem Date: Sun, 3 Dec 2023 18:35:57 +0100 Subject: [PATCH 27/27] changes: correction cargo fmt --- canyon_crud/src/crud.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/canyon_crud/src/crud.rs b/canyon_crud/src/crud.rs index 55ba7ae6..981c24f1 100644 --- a/canyon_crud/src/crud.rs +++ b/canyon_crud/src/crud.rs @@ -311,7 +311,8 @@ fn reorder_params( fn_parser: impl Fn(&&dyn QueryParameter<'_>) -> T, ) -> Vec { let mut ordered_params = vec![]; - let rg = regex::Regex::new(DETECT_PARAMS_IN_QUERY).expect("Error create regex with detect params pattern expression"); + let rg = regex::Regex::new(DETECT_PARAMS_IN_QUERY) + .expect("Error create regex with detect params pattern expression"); for positional_param in rg.find_iter(stmt) { let pp: &str = positional_param.as_str();