1
#[cfg(feature = "mysql")]
2
use crate::constants::MYSQL_DS;
3
#[cfg(feature = "mssql")]
4
use crate::constants::SQL_SERVER_DS;
5

            
6
// Tests for the QueryBuilder available operations within Canyon.
7
///
8
// QueryBuilder are the way of obtain more flexibility that with
9
// the default generated queries, essentially for build the queries
10
// with the SQL filters
11
///
12
use canyon_sql::{
13
    crud::CrudOperations,
14
    query::{operators::Comp, operators::Like, ops::QueryBuilder},
15
};
16

            
17
use crate::tests_models::league::*;
18
use crate::tests_models::player::*;
19
use crate::tests_models::tournament::*;
20

            
21
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
22
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
23
15
#[canyon_sql::macros::canyon_tokio_test]
24
1
fn test_generated_sql_by_the_select_querybuilder() {
25
1
    let mut select_with_joins = League::select_query();
26
4
    select_with_joins
27
        .inner_join("tournament", "league.id", "tournament.league_id")
28
        .left_join("team", "tournament.id", "player.tournament_id")
29
1
        .r#where(LeagueFieldValue::id(&7), Comp::Gt)
30
1
        .and(LeagueFieldValue::name(&"KOREA"), Comp::Eq)
31
1
        .and_values_in(LeagueField::name, &["LCK", "STRANGER THINGS"]);
32
    // .query()
33
    // .await;
34
    // NOTE: We don't have in the docker the generated relationships
35
    // with the joins, so for now, we are just going to check that the
36
    // generated SQL by the SelectQueryBuilder<T> is the spected
37
1
    assert_eq!(
38
1
        select_with_joins.read_sql(),
39
        "SELECT * FROM league INNER JOIN tournament ON league.id = tournament.league_id LEFT JOIN team ON tournament.id = player.tournament_id WHERE id > $1 AND name = $2 AND name IN ($2, $3)"
40
    )
41
}
42

            
43
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
44
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
45
#[cfg(feature = "postgres")]
46
18
#[canyon_sql::macros::canyon_tokio_test]
47
1
fn test_crud_find_with_querybuilder() {
48
    // Find all the leagues with ID less or equals that 7
49
    // and where it's region column value is equals to 'Korea'
50
5
    let filtered_leagues_result: Result<Vec<League>, _> = League::select_query()
51
1
        .r#where(LeagueFieldValue::id(&50), Comp::LtEq)
52
1
        .and(LeagueFieldValue::region(&"KOREA"), Comp::Eq)
53
        .query()
54
4
        .await;
55

            
56
1
    let filtered_leagues: Vec<League> = filtered_leagues_result.unwrap();
57
1
    assert!(!filtered_leagues.is_empty());
58

            
59
1
    let league_idx_0 = filtered_leagues.get(0).unwrap();
60
1
    assert_eq!(league_idx_0.id, 34);
61
1
    assert_eq!(league_idx_0.region, "KOREA");
62
}
63

            
64
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
65
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
66
#[cfg(feature = "postgres")]
67
15
#[canyon_sql::macros::canyon_tokio_test]
68
1
fn test_crud_find_with_querybuilder_and_fulllike() {
69
    // Find all the leagues with "LC" in their name
70
1
    let mut filtered_leagues_result = League::select_query();
71
1
    filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), Like::Full);
72

            
73
1
    assert_eq!(
74
1
        filtered_leagues_result.read_sql(),
75
        "SELECT * FROM league WHERE name LIKE CONCAT('%', CAST($1 AS VARCHAR) ,'%')"
76
    )
77
}
78

            
79
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
80
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
81
#[cfg(feature = "mssql")]
82
15
#[canyon_sql::macros::canyon_tokio_test]
83
1
fn test_crud_find_with_querybuilder_and_fulllike_datasource_mssql() {
84
    // Find all the leagues with "LC" in their name
85
1
    let mut filtered_leagues_result = League::select_query_datasource(SQL_SERVER_DS);
86
1
    filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), Like::Full);
87

            
88
1
    assert_eq!(
89
1
        filtered_leagues_result.read_sql(),
90
        "SELECT * FROM league WHERE name LIKE CONCAT('%', CAST($1 AS VARCHAR) ,'%')"
91
    )
92
}
93

            
94
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
95
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
96
#[cfg(feature = "mysql")]
97
15
#[canyon_sql::macros::canyon_tokio_test]
98
1
fn test_crud_find_with_querybuilder_and_fulllike_datasource_mysql() {
99
    // Find all the leagues with "LC" in their name
100
1
    let mut filtered_leagues_result = League::select_query_datasource(MYSQL_DS);
101
1
    filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), Like::Full);
102

            
103
1
    assert_eq!(
104
1
        filtered_leagues_result.read_sql(),
105
        "SELECT * FROM league WHERE name LIKE CONCAT('%', CAST($1 AS CHAR) ,'%')"
106
    )
107
}
108

            
109
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
110
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
111
#[cfg(feature = "postgres")]
112
14
#[canyon_sql::macros::canyon_tokio_test]
113
1
fn test_crud_find_with_querybuilder_and_leftlike() {
114
    // Find all the leagues whose name ends with "CK"
115
1
    let mut filtered_leagues_result = League::select_query();
116
1
    filtered_leagues_result.r#where(LeagueFieldValue::name(&"CK"), Like::Left);
117

            
118
1
    assert_eq!(
119
1
        filtered_leagues_result.read_sql(),
120
        "SELECT * FROM league WHERE name LIKE CONCAT('%', CAST($1 AS VARCHAR))"
121
    )
122
}
123

            
124
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
125
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
126
#[cfg(feature = "mssql")]
127
13
#[canyon_sql::macros::canyon_tokio_test]
128
1
fn test_crud_find_with_querybuilder_and_leftlike_datasource_mssql() {
129
    // Find all the leagues whose name ends with "CK"
130
1
    let mut filtered_leagues_result = League::select_query();
131
1
    filtered_leagues_result.r#where(LeagueFieldValue::name(&"CK"), Like::Left);
132

            
133
1
    assert_eq!(
134
1
        filtered_leagues_result.read_sql(),
135
        "SELECT * FROM league WHERE name LIKE CONCAT('%', CAST($1 AS VARCHAR))"
136
    )
137
}
138

            
139
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
140
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
141
#[cfg(feature = "mysql")]
142
16
#[canyon_sql::macros::canyon_tokio_test]
143
1
fn test_crud_find_with_querybuilder_and_leftlike_datasource_mysql() {
144
    // Find all the leagues whose name ends with "CK"
145
1
    let mut filtered_leagues_result = League::select_query_datasource(MYSQL_DS);
146
1
    filtered_leagues_result.r#where(LeagueFieldValue::name(&"CK"), Like::Left);
147

            
148
1
    assert_eq!(
149
1
        filtered_leagues_result.read_sql(),
150
        "SELECT * FROM league WHERE name LIKE CONCAT('%', CAST($1 AS CHAR))"
151
    )
152
}
153

            
154
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
155
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
156
#[cfg(feature = "postgres")]
157
15
#[canyon_sql::macros::canyon_tokio_test]
158
1
fn test_crud_find_with_querybuilder_and_rightlike() {
159
    // Find all the leagues whose name starts with "LC"
160
1
    let mut filtered_leagues_result = League::select_query();
161
1
    filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), Like::Right);
162

            
163
1
    assert_eq!(
164
1
        filtered_leagues_result.read_sql(),
165
        "SELECT * FROM league WHERE name LIKE CONCAT(CAST($1 AS VARCHAR) ,'%')"
166
    )
167
}
168

            
169
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
170
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
171
#[cfg(feature = "mssql")]
172
15
#[canyon_sql::macros::canyon_tokio_test]
173
1
fn test_crud_find_with_querybuilder_and_rightlike_datasource_mssql() {
174
    // Find all the leagues whose name starts with "LC"
175
1
    let mut filtered_leagues_result = League::select_query_datasource(SQL_SERVER_DS);
176
1
    filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), Like::Right);
177

            
178
1
    assert_eq!(
179
1
        filtered_leagues_result.read_sql(),
180
        "SELECT * FROM league WHERE name LIKE CONCAT(CAST($1 AS VARCHAR) ,'%')"
181
    )
182
}
183
/// Builds a new SQL statement for retrieves entities of the `T` type, filtered
184
/// with the parameters that modifies the base SQL to SELECT * FROM <entity>
185
#[cfg(feature = "mysql")]
186
15
#[canyon_sql::macros::canyon_tokio_test]
187
1
fn test_crud_find_with_querybuilder_and_rightlike_datasource_mysql() {
188
    // Find all the leagues whose name starts with "LC"
189
1
    let mut filtered_leagues_result = League::select_query_datasource(MYSQL_DS);
190
1
    filtered_leagues_result.r#where(LeagueFieldValue::name(&"LC"), Like::Right);
191

            
192
1
    assert_eq!(
193
1
        filtered_leagues_result.read_sql(),
194
        "SELECT * FROM league WHERE name LIKE CONCAT(CAST($1 AS CHAR) ,'%')"
195
    )
196
}
197

            
198
/// Same than the above but with the specified datasource
199
#[cfg(feature = "mssql")]
200
18
#[canyon_sql::macros::canyon_tokio_test]
201
1
fn test_crud_find_with_querybuilder_datasource_mssql() {
202
    // Find all the players where its ID column value is greater that 50
203
4
    let filtered_find_players = Player::select_query_datasource(SQL_SERVER_DS)
204
1
        .r#where(PlayerFieldValue::id(&50), Comp::Gt)
205
        .query()
206
3
        .await;
207

            
208
1
    assert!(!filtered_find_players.unwrap().is_empty());
209
}
210

            
211
/// Same than the above but with the specified datasource
212
#[cfg(feature = "mysql")]
213
23
#[canyon_sql::macros::canyon_tokio_test]
214
1
fn test_crud_find_with_querybuilder_datasource_mysql() {
215
    // Find all the players where its ID column value is greater that 50
216
4
    let filtered_find_players = Player::select_query_datasource(MYSQL_DS)
217
1
        .r#where(PlayerFieldValue::id(&50), Comp::Gt)
218
        .query()
219
9
        .await;
220

            
221
1
    assert!(!filtered_find_players.unwrap().is_empty());
222
}
223

            
224
/// Updates the values of the range on entries defined by the constraint parameters
225
/// in the database entity
226
#[cfg(feature = "postgres")]
227
19
#[canyon_sql::macros::canyon_tokio_test]
228
1
fn test_crud_update_with_querybuilder() {
229
    // Find all the leagues with ID less or equals that 7
230
    // and where it's region column value is equals to 'Korea'
231
1
    let mut q = League::update_query();
232
3
    q.set(&[
233
        (LeagueField::slug, "Updated with the QueryBuilder"),
234
        (LeagueField::name, "Random"),
235
    ])
236
1
    .r#where(LeagueFieldValue::id(&1), Comp::Gt)
237
1
    .and(LeagueFieldValue::id(&8), Comp::Lt);
238

            
239
    /*  NOTE: Family of QueryBuilders are clone, useful in case of need to read the generated SQL
240
        let qpr = q.clone();
241
        println!("PSQL: {:?}", qpr.read_sql());
242
    */
243

            
244
    // We can now back to the original an throw the query
245
4
    q.query()
246
4
        .await
247
1
        .expect("Failed to update records with the querybuilder");
248

            
249
6
    let found_updated_values = League::select_query()
250
1
        .r#where(LeagueFieldValue::id(&1), Comp::Gt)
251
1
        .and(LeagueFieldValue::id(&7), Comp::Lt)
252
        .query()
253
4
        .await
254
1
        .expect("Failed to retrieve database League entries with the querybuilder");
255

            
256
1
    found_updated_values
257
        .iter()
258
5
        .for_each(|league| assert_eq!(league.slug, "Updated with the QueryBuilder"));
259
}
260

            
261
/// Same as above, but with the specified datasource
262
#[cfg(feature = "mssql")]
263
19
#[canyon_sql::macros::canyon_tokio_test]
264
1
fn test_crud_update_with_querybuilder_datasource_mssql() {
265
    // Find all the leagues with ID less or equals that 7
266
    // and where it's region column value is equals to 'Korea'
267
1
    let mut q = Player::update_query_datasource(SQL_SERVER_DS);
268
6
    q.set(&[
269
        (PlayerField::summoner_name, "Random updated player name"),
270
        (PlayerField::first_name, "I am an updated first name"),
271
    ])
272
1
    .r#where(PlayerFieldValue::id(&1), Comp::Gt)
273
1
    .and(PlayerFieldValue::id(&8), Comp::Lt)
274
    .query()
275
3
    .await
276
1
    .expect("Failed to update records with the querybuilder");
277

            
278
6
    let found_updated_values = Player::select_query_datasource(SQL_SERVER_DS)
279
1
        .r#where(PlayerFieldValue::id(&1), Comp::Gt)
280
1
        .and(PlayerFieldValue::id(&7), Comp::LtEq)
281
        .query()
282
3
        .await
283
1
        .expect("Failed to retrieve database League entries with the querybuilder");
284

            
285
7
    found_updated_values.iter().for_each(|player| {
286
6
        assert_eq!(player.summoner_name, "Random updated player name");
287
6
        assert_eq!(player.first_name, "I am an updated first name");
288
6
    });
289
}
290

            
291
/// Same as above, but with the specified datasource
292
#[cfg(feature = "mysql")]
293
30
#[canyon_sql::macros::canyon_tokio_test]
294
1
fn test_crud_update_with_querybuilder_datasource_mysql() {
295
    // Find all the leagues with ID less or equals that 7
296
    // and where it's region column value is equals to 'Korea'
297

            
298
1
    let mut q = Player::update_query_datasource(MYSQL_DS);
299
6
    q.set(&[
300
        (PlayerField::summoner_name, "Random updated player name"),
301
        (PlayerField::first_name, "I am an updated first name"),
302
    ])
303
1
    .r#where(PlayerFieldValue::id(&1), Comp::Gt)
304
1
    .and(PlayerFieldValue::id(&8), Comp::Lt)
305
    .query()
306
9
    .await
307
1
    .expect("Failed to update records with the querybuilder");
308

            
309
6
    let found_updated_values = Player::select_query_datasource(MYSQL_DS)
310
1
        .r#where(PlayerFieldValue::id(&1), Comp::Gt)
311
1
        .and(PlayerFieldValue::id(&7), Comp::LtEq)
312
        .query()
313
9
        .await
314
1
        .expect("Failed to retrieve database League entries with the querybuilder");
315

            
316
7
    found_updated_values.iter().for_each(|player| {
317
6
        assert_eq!(player.summoner_name, "Random updated player name");
318
6
        assert_eq!(player.first_name, "I am an updated first name");
319
6
    });
320
}
321

            
322
/// Deletes entries from the mapped entity `T` that are in the ranges filtered
323
/// with the QueryBuilder
324
///
325
/// Note if the database is persisted (not created and destroyed on every docker or
326
/// GitHub Action wake up), it won't delete things that already have been deleted,
327
/// but this isn't an error. They just don't exists.
328
#[cfg(feature = "postgres")]
329
20
#[canyon_sql::macros::canyon_tokio_test]
330
1
fn test_crud_delete_with_querybuilder() {
331
6
    Tournament::delete_query()
332
1
        .r#where(TournamentFieldValue::id(&14), Comp::Gt)
333
1
        .and(TournamentFieldValue::id(&16), Comp::Lt)
334
        .query()
335
4
        .await
336
1
        .expect("Error connecting with the database on the delete operation");
337

            
338
3
    assert_eq!(Tournament::find_by_pk(&15).await.unwrap(), None);
339
}
340

            
341
/// Same as the above delete, but with the specified datasource
342
#[cfg(feature = "mssql")]
343
19
#[canyon_sql::macros::canyon_tokio_test]
344
1
fn test_crud_delete_with_querybuilder_datasource_mssql() {
345
6
    Player::delete_query_datasource(SQL_SERVER_DS)
346
1
        .r#where(PlayerFieldValue::id(&120), Comp::Gt)
347
1
        .and(PlayerFieldValue::id(&130), Comp::Lt)
348
        .query()
349
3
        .await
350
1
        .expect("Error connecting with the database when we are going to delete data! :)");
351

            
352
5
    assert!(Player::select_query_datasource(SQL_SERVER_DS)
353
1
        .r#where(PlayerFieldValue::id(&122), Comp::Eq)
354
        .query()
355
3
        .await
356
        .unwrap()
357
        .is_empty());
358
}
359

            
360
/// Same as the above delete, but with the specified datasource
361
#[cfg(feature = "mysql")]
362
29
#[canyon_sql::macros::canyon_tokio_test]
363
1
fn test_crud_delete_with_querybuilder_datasource_mysql() {
364
6
    Player::delete_query_datasource(MYSQL_DS)
365
1
        .r#where(PlayerFieldValue::id(&120), Comp::Gt)
366
1
        .and(PlayerFieldValue::id(&130), Comp::Lt)
367
        .query()
368
8
        .await
369
1
        .expect("Error connecting with the database when we are going to delete data! :)");
370

            
371
5
    assert!(Player::select_query_datasource(MYSQL_DS)
372
1
        .r#where(PlayerFieldValue::id(&122), Comp::Eq)
373
        .query()
374
8
        .await
375
        .unwrap()
376
        .is_empty());
377
}
378

            
379
/// Tests for the generated SQL query after use the
380
/// WHERE clause
381
15
#[canyon_sql::macros::canyon_tokio_test]
382
1
fn test_where_clause() {
383
1
    let mut l = League::select_query();
384
1
    l.r#where(LeagueFieldValue::name(&"LEC"), Comp::Eq);
385

            
386
1
    assert_eq!(l.read_sql(), "SELECT * FROM league WHERE name = $1")
387
}
388

            
389
/// Tests for the generated SQL query after use the
390
/// AND clause
391
15
#[canyon_sql::macros::canyon_tokio_test]
392
1
fn test_and_clause() {
393
1
    let mut l = League::select_query();
394
2
    l.r#where(LeagueFieldValue::name(&"LEC"), Comp::Eq)
395
1
        .and(LeagueFieldValue::id(&10), Comp::LtEq);
396

            
397
1
    assert_eq!(
398
1
        l.read_sql().trim(),
399
        "SELECT * FROM league WHERE name = $1 AND id <= $2"
400
    )
401
}
402

            
403
/// Tests for the generated SQL query after use the
404
/// AND clause
405
15
#[canyon_sql::macros::canyon_tokio_test]
406
1
fn test_and_clause_with_in_constraint() {
407
1
    let mut l = League::select_query();
408
2
    l.r#where(LeagueFieldValue::name(&"LEC"), Comp::Eq)
409
1
        .and_values_in(LeagueField::id, &[1, 7, 10]);
410

            
411
1
    assert_eq!(
412
1
        l.read_sql().trim(),
413
        "SELECT * FROM league WHERE name = $1 AND id IN ($1, $2, $3)"
414
    )
415
}
416

            
417
/// Tests for the generated SQL query after use the
418
/// AND clause
419
14
#[canyon_sql::macros::canyon_tokio_test]
420
1
fn test_or_clause() {
421
1
    let mut l = League::select_query();
422
2
    l.r#where(LeagueFieldValue::name(&"LEC"), Comp::Eq)
423
1
        .or(LeagueFieldValue::id(&10), Comp::LtEq);
424

            
425
1
    assert_eq!(
426
1
        l.read_sql().trim(),
427
        "SELECT * FROM league WHERE name = $1 OR id <= $2"
428
    )
429
}
430

            
431
/// Tests for the generated SQL query after use the
432
/// AND clause
433
16
#[canyon_sql::macros::canyon_tokio_test]
434
1
fn test_or_clause_with_in_constraint() {
435
1
    let mut l = League::select_query();
436
2
    l.r#where(LeagueFieldValue::name(&"LEC"), Comp::Eq)
437
1
        .or_values_in(LeagueField::id, &[1, 7, 10]);
438

            
439
1
    assert_eq!(
440
1
        l.read_sql(),
441
        "SELECT * FROM league WHERE name = $1 OR id IN ($1, $2, $3)"
442
    )
443
}
444

            
445
/// Tests for the generated SQL query after use the
446
/// AND clause
447
15
#[canyon_sql::macros::canyon_tokio_test]
448
1
fn test_order_by_clause() {
449
1
    let mut l = League::select_query();
450
2
    l.r#where(LeagueFieldValue::name(&"LEC"), Comp::Eq)
451
1
        .order_by(LeagueField::id, false);
452

            
453
1
    assert_eq!(
454
1
        l.read_sql(),
455
        "SELECT * FROM league WHERE name = $1 ORDER BY id"
456
    )
457
}