Hello, I want my code to be able to switch in runtime between mysql_db and sqlite_db. It will get that info from a command line arg. but when I import both, I get a conflict of types. I found a half-solution. it can work with when blocks, and changing just a const in the code, or I can split the consts to different files, and compile a few binaries, each targeting a different db backend. But all of this is less than what I hoped for.
The problem is shown concisely here. Cannot refactor code here.
import db_mysql
import db_sqlite
var db : ___.DbConn
if input=="mysql":
db = db_mysql.open("localhost", user, pass, "dbName")
let ok = db.setEncoding("utf8")
else:
db = db_sqlite.open(dbfile, "", "", "")
start(db)
if I do something like this:
start_processing(db: db_sqlite.DbConn | db_mysql.DbConn)
I will get ambiguity errors later on. (Which type did you mean, to take fast_rows from.)
P.S: I thought this is a non-issue due to Nim's structural typing, but most likely I didn't understand the docs.
In other languages, I'd rely on an interface for the function's signature.
The db_sqlite.DbConn | db_mysql.DbConn syntax creates a typeclass, which is a kind of generics that resolves at compile-time.
Instead, use a variant object to create a type that stores either DbConn:
import db_sqlite, db_mysql
type
DbType = enum
dtSqlite
dtMysql
Db = object
case typ: DbType
of dtSqlite:
connSqlite: db_sqlite.DbConn
of dtMysql:
connMysql: db_mysql.DbConn
proc newDb(typ: DbType, connection, user, pass, name: string): Db =
case typ
of dtSqlite:
result = Db(typ: typ, connSqlite: db_sqlite.open(connection, user, pass, name))
of dtMysql:
result = Db(typ: typ, connMysql: db_mysql.open(connection, user, pass, name))
discard result.connMysql.setEncoding "utf8"
Then check the typ field to know which procedure should you call:
proc close(db: var Db) =
case db.typ
of dtSqlite:
db.connSqlite.close()
db.connSqlite = nil
of dtMysql:
db.connMysql.close()
db.connMysql = nil
Playground link (note: playground doesn't have mysql so this won't run)
I think this Nimble package does what you need: https://github.com/jlp765/db
The downside is that then your code will depend on sqlite.dll, mysql.dll etc at the same time and in no language I'm aware of an "interface" solves this problem.
Thank you for the answers Leorize and Araq.
Do you think an object oriented approach, such as making a base class to use, would solve this issue at its core? the correct proc/method would then be resolved at runtime, according to the object.
That makes any fixes and improvement on the common base twice as expensive.
For smaller binaries you can use a compile-time when if you want to only build a single backend. The difference would probably be minimal anyway because Nim does dead-code elimination.