this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

use prepared statements for inserts

+106 -26
+6
src/db/main.odin
··· 25 25 26 26 return id 27 27 } 28 + 29 + DatabaseErrors :: enum { 30 + None, 31 + UniqueConstraint, 32 + UnknownError, 33 + }
+5 -5
src/db/migrations/01-init.sql
··· 1 1 CREATE TABLE migrations ( 2 2 id INTEGER PRIMARY KEY, 3 - name TEXT NOT NULL, 3 + name TEXT NOT NULL UNIQUE, 4 4 applied_at DATE 5 5 ); 6 6 7 7 CREATE TABLE album ( 8 8 id TEXT PRIMARY KEY, 9 9 title TEXT NOT NULL, 10 - mb_id TEXT, 11 - mb_rg_id TEXT 10 + mb_id TEXT UNIQUE, 11 + mb_rg_id TEXT UNIQUE 12 12 ); 13 13 14 14 CREATE TABLE artist ( 15 15 id TEXT PRIMARY KEY, 16 16 name TEXT NOT NULL UNIQUE, 17 - mb_id TEXT, 18 - acoust_id TEXT 17 + mb_id TEXT UNIQUE, 18 + acoust_id TEXT UNIQUE 19 19 ); 20 20 21 21 CREATE TABLE track (
+91 -19
src/db/repo/album.odin
··· 12 12 db: ^sqlite.Connection, 13 13 album: types.Album, 14 14 allocator := context.allocator, 15 - ) -> sqlite.Result_Code { 15 + ) -> ( 16 + new_id: string, 17 + err: db_pkg.DatabaseErrors, 18 + ) { 19 + 20 + ok: bool 21 + mb_id, mb_rg_id: string 16 22 17 23 id := db_pkg.gen_id("album", allocator) 18 - defer delete(id, allocator) 24 + new_id = id 25 + c_id := strings.clone_to_cstring(id, allocator) 26 + c_title := strings.clone_to_cstring(album.title, allocator) 19 27 28 + defer { 29 + delete(c_id, allocator) 30 + delete(c_title, allocator) 31 + } 20 32 21 - params := make([dynamic]sa.Query_Param, 2, 4, allocator) 22 - defer delete_dynamic_array(params) 33 + query: cstring = "INSERT INTO album (id, title, mb_id, mb_rg_id) VALUES (?, ?, ?, ?)" 23 34 24 - params[0] = sa.Query_Param{1, id} 25 - params[1] = sa.Query_Param{2, album.title} 35 + stmt: ^sqlite.Statement 26 36 37 + if rc := sqlite.prepare_v2(db, query, c.int(len(query)), &stmt, nil); rc != .Ok { 38 + return new_id, .UnknownError 39 + } 40 + defer sqlite.finalize(stmt) 27 41 28 - mb_id, mb_rg_id: string 29 - ok: bool 42 + if rc := sqlite.bind_text( 43 + stmt, 44 + param_idx = 1, 45 + param_value = c_id, 46 + param_len = c.int(len(id)), 47 + free = {behaviour = .Static}, 48 + ); rc != .Ok { 49 + fmt.eprintfln("failed to bind value to ArtistId. result code: {}", rc) 50 + return new_id, .UnknownError 51 + } 30 52 31 - mb_id, ok = album.mb_id.? 32 - if ok do append(&params, sa.Query_Param{3, mb_id}) 33 53 34 - mb_rg_id, ok = album.mb_rg_id.? 35 - if ok do append(&params, sa.Query_Param{4, mb_rg_id}) 54 + if rc := sqlite.bind_text( 55 + stmt, 56 + param_idx = 2, 57 + param_value = c_title, 58 + param_len = c.int(len(album.title)), 59 + free = {behaviour = .Static}, 60 + ); rc != .Ok { 61 + fmt.eprintfln("failed to bind value to artist title. result code: {}", rc) 62 + return new_id, .UnknownError 63 + } 36 64 37 - return sa.execute( 38 - db, 39 - "INSERT INTO album (id, title, mb_id, mb_rg_id) VALUES (?, ?, ?, ?)", 40 - params[:], 41 - ) 65 + if mb_id, ok := album.mb_id.?; ok { 66 + c_mb_id := strings.clone_to_cstring(mb_id, allocator) 67 + defer delete(c_mb_id, allocator) 68 + 69 + if rc := sqlite.bind_text( 70 + stmt, 71 + param_idx = 3, 72 + param_value = c_mb_id, 73 + param_len = c.int(len(mb_id)), 74 + free = {behaviour = .Static}, 75 + ); rc != .Ok { 76 + fmt.eprintfln("failed to bind value to mb_id. result code: {}", rc) 77 + return new_id, .UnknownError 78 + } 79 + 80 + } 81 + 82 + 83 + if mb_rg_id, ok := album.mb_rg_id.?; ok { 84 + c_mb_rg_id := strings.clone_to_cstring(mb_rg_id, allocator) 85 + defer delete(c_mb_rg_id, allocator) 86 + 87 + if rc := sqlite.bind_text( 88 + stmt, 89 + param_idx = 4, 90 + param_value = c_mb_rg_id, 91 + param_len = c.int(len(mb_rg_id)), 92 + free = {behaviour = .Static}, 93 + ); rc != .Ok { 94 + fmt.eprintfln("failed to bind value to mb_rg_id. result code: {}", rc) 95 + return new_id, .UnknownError 96 + } 97 + 98 + } 99 + 100 + 101 + fmt.printfln("prepared sql: {}\n", sqlite.expanded_sql(stmt)) 102 + 103 + 104 + rc := sqlite.step(stmt) 105 + fmt.printfln("Step RC: %v", rc) 106 + if (rc == .Constraint) { 107 + return new_id, .UniqueConstraint 108 + } 109 + if (rc != .Done) { 110 + return new_id, .UnknownError 111 + } 112 + 113 + return new_id, .None 42 114 } 43 115 44 116 ··· 59 131 60 132 for album in albums { 61 133 fmt.printfln("Inserting %v", album) 62 - rc = new_album(db, album, allocator) 63 - assert(rc == .Ok) 134 + new_id, err := new_album(db, album, allocator) 135 + assert(err == .None) 64 136 } 65 137 66 138 fmt.printfln("Commiting transaction")
+4 -2
src/db/repo/album.test.odin
··· 52 52 mb_rg_id = "asdf", 53 53 } 54 54 55 - rc := new_album(db, album) 56 - testing.expect(t, rc == .Ok) 55 + new_id, err := new_album(db, album) 56 + fmt.printfln("Error: %v", err) 57 + defer delete(new_id) 58 + testing.expect(t, err == .None) 57 59 58 60 } 59 61