diff --git a/src/boss_record_lib.erl b/src/boss_record_lib.erl index e1f20f3e..0b625de4 100644 --- a/src/boss_record_lib.erl +++ b/src/boss_record_lib.erl @@ -8,6 +8,7 @@ attribute_types/1, database_columns/1, database_table/1, + belongs_to_types/1, convert_value_to_type/2, ensure_loaded/1 ]). @@ -63,6 +64,9 @@ database_table(Module) -> DummyRecord = dummy_record(Module), DummyRecord:database_table(). +belongs_to_types(Module) when is_atom(Module) -> + (dummy_record(Module)):belongs_to_types(). + ensure_loaded(Module) -> case code:ensure_loaded(Module) of {module, Module} -> diff --git a/src/boss_sql_lib.erl b/src/boss_sql_lib.erl index 35bd2950..9777d89a 100644 --- a/src/boss_sql_lib.erl +++ b/src/boss_sql_lib.erl @@ -2,7 +2,9 @@ -export([keytype/1, infer_type_from_id/1, convert_id_condition_to_use_table_ids/1, - is_foreign_key/2 + is_foreign_key/2, + convert_possible_foreign_key/6, + get_retyped_foreign_keys/1 ]). -define(DEFAULT_KEYTYPE, serial). @@ -51,6 +53,33 @@ is_foreign_key(Type, Key) when is_atom(Key) -> end; is_foreign_key(_Type, _Key) -> false. +get_retyped_foreign_keys(Type) when is_atom(Type) -> + % a list of belongs_to-s that use a different module and field names. + % this mainly to reduce the complexity from O(N*M) to O(N*L) + % where N is all fields, M is all of the belongs_to-s, and L is only the differing ones. + lists:foldl(fun ({X, X}, Acc) when is_atom(X) -> + Acc; + ({X, Y}, Acc) when is_atom(X) andalso is_atom(Y) -> + [{X, Y} | Acc] + end, [], boss_record_lib:belongs_to_types(Type)). + +integer_to_id(Val, KeyString) when is_list(KeyString) -> + ModelName = string:substr(KeyString, 1, string:len(KeyString) - string:len("_id")), + ModelName ++ "-" ++ boss_record_lib:convert_value_to_type(Val, string). + +convert_possible_foreign_key(AwkwardAssociations, Type, Key, Value, AttrType, DBColumn) -> + case boss_sql_lib:is_foreign_key(Type, Key) of + true -> + case [ ModuleName || {FieldName, ModuleName} <- AwkwardAssociations, list_to_atom(atom_to_list(FieldName) ++ "_id") =:= Key] of + [] -> + integer_to_id(Value, DBColumn); + [Module] when is_atom(Module) -> + atom_to_list(Module) ++ "-" ++ boss_record_lib:convert_value_to_type(Value, string) + end; + false -> + boss_record_lib:convert_value_to_type(Value, AttrType) + end. + join([], _) -> []; join([List|Lists], Separator) -> lists:flatten([List | [[Separator,Next] || Next <- Lists]]). diff --git a/src/db_adapters/boss_db_adapter_mysql.erl b/src/db_adapters/boss_db_adapter_mysql.erl index b27d66eb..0aec809c 100644 --- a/src/db_adapters/boss_db_adapter_mysql.erl +++ b/src/db_adapters/boss_db_adapter_mysql.erl @@ -216,13 +216,16 @@ migration_done(Pid, Tag, down) -> % internal -integer_to_id(Val, KeyString) -> - ModelName = string:substr(KeyString, 1, string:len(KeyString) - string:len("_id")), - ModelName ++ "-" ++ integer_to_list(Val). +%% integer_to_id(Val, KeyString) -> +%% ModelName = string:substr(KeyString, 1, string:len(KeyString) - string:len("_id")), +%% ModelName ++ "-" ++ integer_to_list(Val). activate_record(Record, Metadata, Type) -> AttributeTypes = boss_record_lib:attribute_types(Type), AttributeColumns = boss_record_lib:database_columns(Type), + + RetypedForeignKeys = boss_sql_lib:get_retyped_foreign_keys(Type), + apply(Type, new, lists:map(fun (id) -> DBColumn = proplists:get_value('id', AttributeColumns), @@ -236,10 +239,7 @@ activate_record(Record, Metadata, Type) -> undefined -> undefined; {datetime, DateTime} -> boss_record_lib:convert_value_to_type(DateTime, AttrType); Val -> - case boss_sql_lib:is_foreign_key(Type, Key) of - true -> integer_to_id(Val, DBColumn); - false -> boss_record_lib:convert_value_to_type(Val, AttrType) - end + boss_sql_lib:convert_possible_foreign_key(RetypedForeignKeys, Type, Key, Val, AttrType, DBColumn) end end, boss_record_lib:attribute_names(Type))). diff --git a/src/db_adapters/boss_db_adapter_pgsql.erl b/src/db_adapters/boss_db_adapter_pgsql.erl index a37c9045..f8fcde5d 100644 --- a/src/db_adapters/boss_db_adapter_pgsql.erl +++ b/src/db_adapters/boss_db_adapter_pgsql.erl @@ -190,6 +190,9 @@ integer_to_id(Val, KeyString) -> activate_record(Record, Metadata, Type) -> AttributeTypes = boss_record_lib:attribute_types(Type), AttributeColumns = boss_record_lib:database_columns(Type), + + RetypedForeignKeys = boss_sql_lib:get_retyped_foreign_keys(Type), + apply(Type, new, lists:map(fun (id) -> DBColumn = proplists:get_value('id', AttributeColumns), @@ -203,10 +206,7 @@ activate_record(Record, Metadata, Type) -> undefined -> undefined; null -> undefined; Val -> - case boss_sql_lib:is_foreign_key(Type, Key) of - true -> integer_to_id(Val, DBColumn); - false -> boss_record_lib:convert_value_to_type(Val, AttrType) - end + boss_sql_lib:convert_possible_foreign_key(RetypedForeignKeys, Type, Key, Val, AttrType, DBColumn) end end, boss_record_lib:attribute_names(Type))).