Everything works well and good structure.
This commit is contained in:
365
Sources/MusicBrainz/SearchAction.swift
Normal file
365
Sources/MusicBrainz/SearchAction.swift
Normal file
@@ -0,0 +1,365 @@
|
||||
import Foundation
|
||||
|
||||
public struct MusicBrainzSearchAction<T: MusicBrainzSearchable>: Sendable {
|
||||
public let entity: MusicBrainzEntity
|
||||
public let query: String
|
||||
|
||||
fileprivate static func buildQuery(_ fields: [String: Any?], raw: String?) -> String {
|
||||
var parts: [String] = []
|
||||
for (key, value) in fields {
|
||||
if let value {
|
||||
let stringValue: String
|
||||
if let val = value as? String {
|
||||
stringValue = val
|
||||
} else if let val = value as? CustomStringConvertible {
|
||||
stringValue = val.description
|
||||
} else if let val = value as? (any RawRepresentable),
|
||||
let rawVal = val.rawValue as? String
|
||||
{
|
||||
stringValue = rawVal
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
if !stringValue.isEmpty {
|
||||
let escaped = stringValue.replacingOccurrences(of: "\"", with: "\\\"")
|
||||
parts.append("\(key):\"\(escaped)\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
if let raw, !raw.isEmpty {
|
||||
parts.append(raw)
|
||||
}
|
||||
return parts.joined(separator: " AND ")
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == Area {
|
||||
public static func area(
|
||||
name: String? = nil,
|
||||
type: String? = nil,
|
||||
iso: String? = nil,
|
||||
aid: String? = nil,
|
||||
alias: String? = nil,
|
||||
begin: String? = nil,
|
||||
comment: String? = nil,
|
||||
end: String? = nil,
|
||||
ended: Bool? = nil,
|
||||
sortname: String? = nil,
|
||||
tag: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"area": name, "type": type, "iso": iso, "aid": aid,
|
||||
"alias": alias, "begin": begin, "comment": comment, "end": end,
|
||||
"ended": ended?.description, "sortname": sortname, "tag": tag,
|
||||
], raw: raw)
|
||||
return .init(entity: .area, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == Artist {
|
||||
public static func artist(
|
||||
name: String? = nil,
|
||||
gender: Gender? = nil,
|
||||
country: Country? = nil,
|
||||
type: ArtistType? = nil,
|
||||
alias: String? = nil,
|
||||
area: String? = nil,
|
||||
arid: String? = nil,
|
||||
begin: String? = nil,
|
||||
beginarea: String? = nil,
|
||||
comment: String? = nil,
|
||||
end: String? = nil,
|
||||
endarea: String? = nil,
|
||||
ended: Bool? = nil,
|
||||
ipi: String? = nil,
|
||||
isni: String? = nil,
|
||||
sortname: String? = nil,
|
||||
tag: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"artist": name, "gender": gender?.rawValue, "country": country?.rawValue,
|
||||
"type": type?.rawValue,
|
||||
"alias": alias, "area": area, "arid": arid, "begin": begin, "beginarea": beginarea,
|
||||
"comment": comment, "end": end, "endarea": endarea, "ended": ended?.description,
|
||||
"ipi": ipi, "isni": isni, "sortname": sortname, "tag": tag,
|
||||
], raw: raw)
|
||||
return .init(entity: .artist, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == Event {
|
||||
public static func event(
|
||||
name: String? = nil,
|
||||
type: String? = nil,
|
||||
artist: String? = nil,
|
||||
place: String? = nil,
|
||||
aid: String? = nil,
|
||||
area: String? = nil,
|
||||
arid: String? = nil,
|
||||
begin: String? = nil,
|
||||
comment: String? = nil,
|
||||
end: String? = nil,
|
||||
ended: Bool? = nil,
|
||||
eid: String? = nil,
|
||||
pid: String? = nil,
|
||||
tag: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"event": name, "type": type, "artist": artist, "place": place,
|
||||
"aid": aid, "area": area, "arid": arid, "begin": begin,
|
||||
"comment": comment, "end": end, "ended": ended?.description,
|
||||
"eid": eid, "pid": pid, "tag": tag,
|
||||
], raw: raw)
|
||||
return .init(entity: .event, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == Instrument {
|
||||
public static func instrument(
|
||||
name: String? = nil,
|
||||
type: String? = nil,
|
||||
description: String? = nil,
|
||||
alias: String? = nil,
|
||||
comment: String? = nil,
|
||||
iid: String? = nil,
|
||||
tag: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"instrument": name, "type": type, "description": description,
|
||||
"alias": alias, "comment": comment, "iid": iid, "tag": tag,
|
||||
], raw: raw)
|
||||
return .init(entity: .instrument, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == Label {
|
||||
public static func label(
|
||||
name: String? = nil,
|
||||
type: String? = nil,
|
||||
code: String? = nil,
|
||||
country: Country? = nil,
|
||||
alias: String? = nil,
|
||||
area: String? = nil,
|
||||
begin: String? = nil,
|
||||
comment: String? = nil,
|
||||
end: String? = nil,
|
||||
ended: Bool? = nil,
|
||||
ipi: String? = nil,
|
||||
isni: String? = nil,
|
||||
laid: String? = nil,
|
||||
sortname: String? = nil,
|
||||
tag: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"label": name, "type": type, "code": code, "country": country?.rawValue,
|
||||
"alias": alias, "area": area, "begin": begin, "comment": comment,
|
||||
"end": end, "ended": ended?.description, "ipi": ipi, "isni": isni,
|
||||
"laid": laid, "sortname": sortname, "tag": tag,
|
||||
], raw: raw)
|
||||
return .init(entity: .label, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == Place {
|
||||
public static func place(
|
||||
name: String? = nil,
|
||||
type: String? = nil,
|
||||
address: String? = nil,
|
||||
area: String? = nil,
|
||||
alias: String? = nil,
|
||||
begin: String? = nil,
|
||||
comment: String? = nil,
|
||||
end: String? = nil,
|
||||
ended: Bool? = nil,
|
||||
lat: String? = nil,
|
||||
long: String? = nil,
|
||||
pid: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"place": name, "type": type, "address": address, "area": area,
|
||||
"alias": alias, "begin": begin, "comment": comment, "end": end,
|
||||
"ended": ended?.description, "lat": lat, "long": long, "pid": pid,
|
||||
], raw: raw)
|
||||
return .init(entity: .place, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == Recording {
|
||||
public static func recording(
|
||||
title: String? = nil,
|
||||
artist: String? = nil,
|
||||
release: String? = nil,
|
||||
isrc: String? = nil,
|
||||
arid: String? = nil,
|
||||
comment: String? = nil,
|
||||
country: Country? = nil,
|
||||
date: String? = nil,
|
||||
dur: String? = nil,
|
||||
firstreleasedate: String? = nil,
|
||||
format: String? = nil,
|
||||
number: String? = nil,
|
||||
position: String? = nil,
|
||||
primarytype: String? = nil,
|
||||
reid: String? = nil,
|
||||
rgid: String? = nil,
|
||||
rid: String? = nil,
|
||||
secondarytype: String? = nil,
|
||||
status: String? = nil,
|
||||
tag: String? = nil,
|
||||
tid: String? = nil,
|
||||
tnum: String? = nil,
|
||||
video: Bool? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"recording": title, "artist": artist, "release": release, "isrc": isrc,
|
||||
"arid": arid, "comment": comment, "country": country?.rawValue, "date": date,
|
||||
"dur": dur, "firstreleasedate": firstreleasedate, "format": format,
|
||||
"number": number, "position": position, "primarytype": primarytype,
|
||||
"reid": reid, "rgid": rgid, "rid": rid, "secondarytype": secondarytype,
|
||||
"status": status, "tag": tag, "tid": tid, "tnum": tnum, "video": video?.description,
|
||||
], raw: raw)
|
||||
return .init(entity: .recording, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == Release {
|
||||
public static func release(
|
||||
title: String? = nil,
|
||||
artist: String? = nil,
|
||||
label: String? = nil,
|
||||
barcode: String? = nil,
|
||||
status: String? = nil,
|
||||
arid: String? = nil,
|
||||
asin: String? = nil,
|
||||
catno: String? = nil,
|
||||
comment: String? = nil,
|
||||
country: Country? = nil,
|
||||
date: String? = nil,
|
||||
discids: String? = nil,
|
||||
format: String? = nil,
|
||||
laid: String? = nil,
|
||||
mediums: String? = nil,
|
||||
primarytype: String? = nil,
|
||||
puid: String? = nil,
|
||||
reid: String? = nil,
|
||||
rgid: String? = nil,
|
||||
script: String? = nil,
|
||||
secondarytype: String? = nil,
|
||||
tag: String? = nil,
|
||||
tracks: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"release": title, "artist": artist, "label": label, "barcode": barcode,
|
||||
"status": status,
|
||||
"arid": arid, "asin": asin, "catno": catno, "comment": comment,
|
||||
"country": country?.rawValue,
|
||||
"date": date, "discids": discids, "format": format, "laid": laid,
|
||||
"mediums": mediums,
|
||||
"primarytype": primarytype, "puid": puid, "reid": reid, "rgid": rgid,
|
||||
"script": script,
|
||||
"secondarytype": secondarytype, "tag": tag, "tracks": tracks,
|
||||
], raw: raw)
|
||||
return .init(entity: .release, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == ReleaseGroup {
|
||||
public static func releaseGroup(
|
||||
title: String? = nil,
|
||||
artist: String? = nil,
|
||||
type: String? = nil,
|
||||
arid: String? = nil,
|
||||
comment: String? = nil,
|
||||
primarytype: String? = nil,
|
||||
rgid: String? = nil,
|
||||
releases: String? = nil,
|
||||
secondarytype: String? = nil,
|
||||
status: String? = nil,
|
||||
tag: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"releasegroup": title, "artist": artist, "type": type, "arid": arid,
|
||||
"comment": comment, "primarytype": primarytype, "rgid": rgid,
|
||||
"releases": releases, "secondarytype": secondarytype, "status": status, "tag": tag,
|
||||
], raw: raw)
|
||||
return .init(entity: .releaseGroup, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == Series {
|
||||
public static func series(
|
||||
name: String? = nil,
|
||||
type: String? = nil,
|
||||
alias: String? = nil,
|
||||
comment: String? = nil,
|
||||
sid: String? = nil,
|
||||
tag: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"series": name, "type": type, "alias": alias, "comment": comment,
|
||||
"sid": sid, "tag": tag,
|
||||
], raw: raw)
|
||||
return .init(entity: .series, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == Work {
|
||||
public static func work(
|
||||
title: String? = nil,
|
||||
artist: String? = nil,
|
||||
type: String? = nil,
|
||||
iswc: String? = nil,
|
||||
alias: String? = nil,
|
||||
arid: String? = nil,
|
||||
comment: String? = nil,
|
||||
lang: String? = nil,
|
||||
tag: String? = nil,
|
||||
wid: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"work": title, "artist": artist, "type": type, "iswc": iswc,
|
||||
"alias": alias, "arid": arid, "comment": comment, "lang": lang,
|
||||
"tag": tag, "wid": wid,
|
||||
], raw: raw)
|
||||
return .init(entity: .work, query: q)
|
||||
}
|
||||
}
|
||||
|
||||
extension MusicBrainzSearchAction where T == URLReference {
|
||||
public static func url(
|
||||
resource: String? = nil,
|
||||
targettype: String? = nil,
|
||||
targetid: String? = nil,
|
||||
uid: String? = nil,
|
||||
raw: String? = nil
|
||||
) -> Self {
|
||||
let q = buildQuery(
|
||||
[
|
||||
"url": resource, "targettype": targettype, "targetid": targetid, "uid": uid,
|
||||
], raw: raw)
|
||||
return .init(entity: .url, query: q)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user