this repo has no description
0
fork

Configure Feed

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

artist and album generation

+305 -127
+7
src/core/types.odin
··· 27 27 mb_rg_id: Maybe(string), // MUSICBRAINZ_RELEASEGROUPID, 28 28 } 29 29 30 + // Junctions 31 + ArtistAlbum :: struct { 32 + artist_id: string, 33 + album_id: string, 34 + } 30 35 36 + 37 + // Api 31 38 AlbumFull :: struct { 32 39 album: Album, 33 40 artists: []Artist,
-1
src/db/repo/album.odin
··· 18 18 ) { 19 19 20 20 fmt.printfln("New Album: %#v", album) 21 - 22 21 ok: bool 23 22 24 23 id := db_pkg.gen_id("album", allocator)
+99 -116
src/db/repo/artist.odin
··· 4 4 import sqlite "../../../vendor/sqlite" 5 5 import sa "../../../vendor/sqlite/addons" 6 6 import types "../../core" 7 + import "core:c" 7 8 import "core:fmt" 8 9 import "core:mem" 10 + import "core:strings" 9 11 import "core:testing" 10 12 11 13 new_artist :: proc( 12 14 db: ^sqlite.Connection, 13 15 artist: types.Artist, 14 16 allocator := context.allocator, 15 - ) -> sqlite.Result_Code { 17 + ) -> ( 18 + new_id: string, 19 + err: db_pkg.DatabaseErrors, 20 + ) { 21 + 22 + fmt.printfln("New artist: %#v", artist) 23 + ok: bool 16 24 17 25 id := db_pkg.gen_id("artist", allocator) 18 - defer delete(id, allocator) 26 + new_id = id 19 27 28 + c_id := strings.clone_to_cstring(id, allocator) 29 + c_name := strings.clone_to_cstring(artist.name, allocator) 20 30 21 - params := make([dynamic]sa.Query_Param, 2, 4, allocator) 22 - defer delete_dynamic_array(params) 23 - params[0] = sa.Query_Param{1, id} 24 - params[1] = sa.Query_Param{2, artist.name} 31 + defer { 32 + delete(c_id, allocator) 33 + delete(c_name, allocator) 34 + } 25 35 36 + query: cstring = "INSERT INTO artist (id, name, mb_id, acoust_id) VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING" 26 37 27 - mb_id, acoust_id: string 28 - ok: bool 38 + stmt: ^sqlite.Statement 29 39 30 - mb_id, ok = artist.mb_id.? 31 - if ok do append(&params, sa.Query_Param{3, mb_id}) 40 + 41 + if rc := sqlite.prepare_v2(db, query, c.int(len(query)), &stmt, nil); rc != .Ok { 42 + return new_id, .UnknownError 43 + } 44 + defer sqlite.finalize(stmt) 45 + 46 + 47 + if rc := sqlite.bind_text( 48 + stmt, 49 + param_idx = 1, 50 + param_value = c_id, 51 + param_len = c.int(len(id)), 52 + free = {behaviour = .Static}, 53 + ); rc != .Ok { 54 + fmt.eprintfln("failed to bind value to ArtistId. result code: {}", rc) 55 + return new_id, .UnknownError 56 + } 32 57 33 - acoust_id, ok = artist.acoust_id.? 34 - if ok do append(&params, sa.Query_Param{4, acoust_id}) 58 + if rc := sqlite.bind_text( 59 + stmt, 60 + param_idx = 2, 61 + param_value = c_name, 62 + param_len = c.int(len(artist.name)), 63 + free = {behaviour = .Static}, 64 + ); rc != .Ok { 65 + fmt.eprintfln("failed to bind value to artist name. result code: {}", rc) 66 + return new_id, .UnknownError 67 + } 68 + 69 + 70 + c_mb_id, c_acoust_id: cstring 71 + defer delete(c_mb_id, allocator) 72 + defer delete(c_acoust_id, allocator) 73 + 74 + if mb_id, ok := artist.mb_id.?; ok { 75 + c_mb_id = strings.clone_to_cstring(mb_id, allocator) 76 + fmt.printfln("%s %s", mb_id, c_mb_id) 77 + 78 + if rc := sqlite.bind_text( 79 + stmt, 80 + param_idx = 3, 81 + param_value = c_mb_id, 82 + param_len = c.int(len(mb_id)), 83 + free = {behaviour = .Static}, 84 + ); rc != .Ok { 85 + fmt.eprintfln("failed to bind value to mb_id. result code: {}", rc) 86 + return new_id, .UnknownError 87 + } 88 + } 89 + 90 + 91 + if acoust_id, ok := artist.acoust_id.?; ok { 92 + c_acoust_id = strings.clone_to_cstring(acoust_id, allocator) 93 + fmt.printfln("%s %s", acoust_id, c_acoust_id) 94 + 95 + if rc := sqlite.bind_text( 96 + stmt, 97 + param_idx = 4, 98 + param_value = c_acoust_id, 99 + param_len = c.int(len(acoust_id)), 100 + free = {behaviour = .Static}, 101 + ); rc != .Ok { 102 + fmt.eprintfln("failed to bind value to acoust_id. result code: {}", rc) 103 + return new_id, .UnknownError 104 + } 105 + } 106 + 107 + fmt.printfln("prepared sql: {}\n", sqlite.expanded_sql(stmt)) 108 + 109 + rc := sqlite.step(stmt) 110 + fmt.printfln("Step RC: %v", rc) 111 + if (rc == .Constraint) { 112 + return new_id, .UniqueConstraint 113 + } 114 + if (rc != .Done) { 115 + return new_id, .UnknownError 116 + } 117 + 118 + return new_id, .None 119 + 35 120 36 - return sa.execute( 37 - db, 38 - "INSERT INTO artist (id, name, mb_id, acoust_id) VALUES (?, ?, ?, ?)", 39 - params[:], 40 - ) 41 121 } 42 122 43 123 new_artist_batch :: proc( ··· 57 137 58 138 for artist in artists { 59 139 fmt.printfln("Inserting %v", artist) 60 - rc = new_artist(db, artist, allocator) 61 - assert(rc == .Ok) 140 + new_id, err := new_artist(db, artist, allocator) 141 + assert(err == .None) 62 142 } 63 143 64 144 fmt.printfln("Commiting transaction") ··· 67 147 68 148 return rc 69 149 } 70 - 71 - 72 - // ================ 73 - // Tests 74 - // ================ 75 - 76 - // @(test) 77 - // should_create_new_artist :: proc(t: ^testing.T) { 78 - // 79 - // track: mem.Tracking_Allocator 80 - // mem.tracking_allocator_init(&track, context.allocator, context.allocator) 81 - // context.allocator = mem.tracking_allocator(&track) 82 - // defer { 83 - // if len(track.allocation_map) > 0 { 84 - // fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map)) 85 - // for _, entry in track.allocation_map { 86 - // fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location) 87 - // } 88 - // } 89 - // if len(track.bad_free_array) > 0 { 90 - // fmt.eprintf("=== %v incorrect frees: ===\n", len(track.bad_free_array)) 91 - // for entry in track.bad_free_array { 92 - // fmt.eprintf("- %p @ %v\n", entry.memory, entry.location) 93 - // } 94 - // } 95 - // mem.tracking_allocator_destroy(&track) 96 - // } 97 - // 98 - // 99 - // db: ^sqlite.Connection 100 - // 101 - // if rc := sqlite.open(db_url, &db); rc != .Ok { 102 - // fmt.panicf("failed to open database. result code {}", rc) 103 - // } 104 - // fmt.printfln("connected to database") 105 - // 106 - // defer { 107 - // sqlite.close(db) 108 - // fmt.printfln("\nconnection closed") 109 - // } 110 - // 111 - // artist := types.Artist { 112 - // id = "test", 113 - // name = "PinkPantheres", 114 - // mb_id = "asdf", 115 - // acoust_id = "123", 116 - // } 117 - // 118 - // rc := new_artist(db, artist, context.allocator) 119 - // testing.expect(t, rc == .Ok) 120 - // } 121 - 122 - @(test) 123 - should_create_new_artist_batch :: proc(t: ^testing.T) { 124 - 125 - 126 - track: mem.Tracking_Allocator 127 - mem.tracking_allocator_init(&track, context.allocator, context.allocator) 128 - context.allocator = mem.tracking_allocator(&track) 129 - defer { 130 - if len(track.allocation_map) > 0 { 131 - fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map)) 132 - for _, entry in track.allocation_map { 133 - fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location) 134 - } 135 - } 136 - if len(track.bad_free_array) > 0 { 137 - fmt.eprintf("=== %v incorrect frees: ===\n", len(track.bad_free_array)) 138 - for entry in track.bad_free_array { 139 - fmt.eprintf("- %p @ %v\n", entry.memory, entry.location) 140 - } 141 - } 142 - mem.tracking_allocator_destroy(&track) 143 - } 144 - 145 - 146 - db: ^sqlite.Connection 147 - 148 - if rc := sqlite.open(db_pkg.db_url, &db); rc != .Ok { 149 - fmt.panicf("failed to open database. result code {}", rc) 150 - } 151 - fmt.printfln("connected to database") 152 - 153 - defer { 154 - sqlite.close(db) 155 - fmt.printfln("connection closed") 156 - } 157 - 158 - artists := []types.Artist { 159 - {id = "test1", name = "PinkPantheres1", mb_id = "asdf", acoust_id = "123"}, 160 - {id = "test2", name = "PinkPantheres2", mb_id = "asdf", acoust_id = "123"}, 161 - {id = "test3", name = "PinkPantheres3", mb_id = "asdf", acoust_id = "123"}, 162 - } 163 - 164 - rc := new_artist_batch(db, artists, context.allocator) 165 - testing.expect(t, rc == .Ok) 166 - }
+101
src/db/repo/artist.test.odin
··· 1 + package repo 2 + 3 + import db_pkg "../" 4 + import sqlite "../../../vendor/sqlite" 5 + import types "../../core" 6 + import "core:fmt" 7 + import "core:mem" 8 + import "core:testing" 9 + 10 + 11 + @(test) 12 + should_create_new_artist :: proc(t: ^testing.T) { 13 + 14 + track: mem.Tracking_Allocator 15 + mem.tracking_allocator_init(&track, context.allocator, context.allocator) 16 + context.allocator = mem.tracking_allocator(&track) 17 + defer { 18 + if len(track.allocation_map) > 0 { 19 + fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map)) 20 + for _, entry in track.allocation_map { 21 + fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location) 22 + } 23 + } 24 + if len(track.bad_free_array) > 0 { 25 + fmt.eprintf("=== %v incorrect frees: ===\n", len(track.bad_free_array)) 26 + for entry in track.bad_free_array { 27 + fmt.eprintf("- %p @ %v\n", entry.memory, entry.location) 28 + } 29 + } 30 + mem.tracking_allocator_destroy(&track) 31 + } 32 + 33 + 34 + db: ^sqlite.Connection 35 + 36 + if rc := sqlite.open(db_pkg.db_url, &db); rc != .Ok { 37 + fmt.panicf("failed to open database. result code {}", rc) 38 + } 39 + fmt.printfln("connected to database") 40 + 41 + defer { 42 + sqlite.close(db) 43 + fmt.printfln("\nconnection closed") 44 + } 45 + 46 + artist := types.Artist { 47 + id = "test", 48 + name = "PinkPantheres", 49 + mb_id = "asdf", 50 + acoust_id = "123", 51 + } 52 + 53 + new_id, err := new_artist(db, artist, context.allocator) 54 + testing.expect(t, err == .None) 55 + } 56 + 57 + @(test) 58 + should_create_new_artist_batch :: proc(t: ^testing.T) { 59 + 60 + 61 + track: mem.Tracking_Allocator 62 + mem.tracking_allocator_init(&track, context.allocator, context.allocator) 63 + context.allocator = mem.tracking_allocator(&track) 64 + defer { 65 + if len(track.allocation_map) > 0 { 66 + fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map)) 67 + for _, entry in track.allocation_map { 68 + fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location) 69 + } 70 + } 71 + if len(track.bad_free_array) > 0 { 72 + fmt.eprintf("=== %v incorrect frees: ===\n", len(track.bad_free_array)) 73 + for entry in track.bad_free_array { 74 + fmt.eprintf("- %p @ %v\n", entry.memory, entry.location) 75 + } 76 + } 77 + mem.tracking_allocator_destroy(&track) 78 + } 79 + 80 + 81 + db: ^sqlite.Connection 82 + 83 + if rc := sqlite.open(db_pkg.db_url, &db); rc != .Ok { 84 + fmt.panicf("failed to open database. result code {}", rc) 85 + } 86 + fmt.printfln("connected to database") 87 + 88 + defer { 89 + sqlite.close(db) 90 + fmt.printfln("connection closed") 91 + } 92 + 93 + artists := []types.Artist { 94 + {id = "test1", name = "PinkPantheres1", mb_id = "asdf", acoust_id = "123"}, 95 + {id = "test2", name = "PinkPantheres2", mb_id = "asdf", acoust_id = "123"}, 96 + {id = "test3", name = "PinkPantheres3", mb_id = "asdf", acoust_id = "123"}, 97 + } 98 + 99 + rc := new_artist_batch(db, artists, context.allocator) 100 + testing.expect(t, rc == .Ok) 101 + }
+75
src/db/repo/junctions.odin
··· 1 + package repo 2 + 3 + import db_pkg "../" 4 + import sqlite "../../../vendor/sqlite" 5 + import sa "../../../vendor/sqlite/addons" 6 + import types "../../core" 7 + import "core:c" 8 + import "core:fmt" 9 + import "core:strings" 10 + 11 + new_artist_album :: proc( 12 + db: ^sqlite.Connection, 13 + a: types.ArtistAlbum, 14 + allocator := context.allocator, 15 + ) -> db_pkg.DatabaseErrors { 16 + 17 + fmt.printfln("New Artist<->Album $#v", a) 18 + ok: bool 19 + 20 + c_artist_id := strings.clone_to_cstring(a.artist_id, allocator) 21 + c_album_id := strings.clone_to_cstring(a.album_id, allocator) 22 + 23 + defer { 24 + delete(c_artist_id, allocator) 25 + delete(c_album_id, allocator) 26 + } 27 + 28 + query: cstring = "INSERT INTO artist_album (artist_id, album_id) VALUES (?, ?) ON CONFLICT DO NOTHING" 29 + 30 + stmt: ^sqlite.Statement 31 + 32 + if rc := sqlite.prepare_v2(db, query, c.int(len(query)), &stmt, nil); rc != .Ok { 33 + return .UnknownError 34 + } 35 + defer sqlite.finalize(stmt) 36 + 37 + 38 + if rc := sqlite.bind_text( 39 + stmt, 40 + param_idx = 1, 41 + param_value = c_artist_id, 42 + param_len = c.int(len(a.artist_id)), 43 + free = {behaviour = .Static}, 44 + ); rc != .Ok { 45 + fmt.eprintfln("failed to bind value to ArtistId. result code: {}", rc) 46 + return .UnknownError 47 + } 48 + 49 + 50 + if rc := sqlite.bind_text( 51 + stmt, 52 + param_idx = 2, 53 + param_value = c_album_id, 54 + param_len = c.int(len(a.album_id)), 55 + free = {behaviour = .Static}, 56 + ); rc != .Ok { 57 + fmt.eprintfln("failed to bind value to albumId. result code: {}", rc) 58 + return .UnknownError 59 + } 60 + 61 + 62 + fmt.printfln("prepared sql: {}\n", sqlite.expanded_sql(stmt)) 63 + 64 + rc := sqlite.step(stmt) 65 + fmt.printfln("Step RC: %v", rc) 66 + if (rc == .Constraint) { 67 + return .UniqueConstraint 68 + } 69 + if (rc != .Done) { 70 + return .UnknownError 71 + } 72 + 73 + return .None 74 + 75 + }
+23 -10
src/library/sync.odin
··· 78 78 assert(ferr == nil) 79 79 80 80 flac, flac_err := formats.flac_read(file) 81 + defer formats.destroy_vorbis_comment(flac) 81 82 82 83 os.close(file) 83 84 assert(flac_err == nil) ··· 90 91 } 91 92 92 93 artist := types.Artist { 93 - id = "", 94 - name = flac.album_artist, 94 + id = "", 95 + name = flac.album_artist, 96 + mb_id = flac.mb_artist_id, 95 97 } 96 98 97 99 fmt.printfln("Flac Comment %#v, artist %#v album %#v", flac, artist, album) 98 100 99 - new_id, err := db.new_album(db_conn, album) 100 - defer delete(new_id) 101 - assert(err == .None || err == .UniqueConstraint) 102 - fmt.printfln("New album |%v| with id |%v|", album.title, new_id) 101 + new_album_id, album_err := db.new_album(db_conn, album) 102 + defer delete(new_album_id) 103 + assert(album_err == .None || album_err == .UniqueConstraint) 104 + fmt.printfln("New album |%v| with id |%v|", album.title, new_album_id) 105 + 106 + new_artist_id, artist_err := db.new_artist(db_conn, artist) 107 + defer delete(new_artist_id) 108 + assert(artist_err == .None || artist_err == .UniqueConstraint) 109 + fmt.printfln("New artist |%v| with id |%v|", artist.name, new_artist_id) 110 + 111 + if (flac.album_artist == artist.name) { 112 + artist_album := types.ArtistAlbum { 113 + album_id = new_album_id, 114 + artist_id = new_artist_id, 115 + } 103 116 104 - rc = db.new_artist(db_conn, artist) 105 - assert(rc == .Ok) 106 - formats.destroy_vorbis_comment(flac) 107 - } 117 + artist_album_err := db.new_artist_album(db_conn, artist_album) 118 + assert(artist_err == .None || artist_err == .UniqueConstraint) 108 119 120 + } 121 + } 109 122 }