granite
granite copied to clipboard
Psuedo Arrays
Hi, at my organization (@ulayer) we are interested in the ability for Granite to have a sort of Psuedo Arrays to avoid needing to write complex custom setter and getter methods.
Context: Our users want to be able to share their Virtual Machines with trusted contacts. To accomplish that we currently have a String field that looks like @allowed_clients = "1,2,5,6,8,"
and so forth. Our model for Virtual Machines has two methods like:
##
# Get Allowed Clients
##
def get_allowed_clients
numbers = [] of Int32
clients = [] of BlestaClient
if a = @allowed_clients
nums_arr = a.split(',')
else
return nil
end
if (nums = nums_arr)
nums.pop
nums.each do |n|
if (num = n.to_i32)
numbers.push(num)
end
end
else
return nil
end
numbers.each do |num|
if (client = BlestaClient.find_by(id_value: num))
clients.push(client)
end
end
return clients
end
##
# Set Allowed Clients
##
def set_allowed_clients(clients_string)
valid_clients = [] of Int32
valid_clients_string = ""
if ((clients = clients_string) && (clients_array = clients.split(",")))
clients_array.each do |num|
if ((client = BlestaClient.find_by(id_value: num)) && (client_id = client.id_value))
valid_clients.push(client_id)
end
end
end
valid_clients.each do |client|
valid_clients_string = "#{valid_clients_string}#{client},"
end
@allowed_clients = valid_clients_string
end
##
# Check if Client is allowed
##
def check_if_client_is_allowed(client_id)
numbers = [] of Int32
if a = @allowed_clients
nums_arr = a.split(',')
else
return nil
end
if (nums = nums_arr)
nums.pop
nums.each do |n|
if (num = n.to_i32)
numbers.push(num)
end
end
else
return nil
end
numbers.each do |num|
if (client_id == num)
return true
end
end
return nil
end
We would like to be able to use the storage of text/strings in the database to have "val,val,val,val" but still take advantage of Crystal's type casting. Instead of having column allowed_clients : String?
we would have column allowed_clients : Array(Int32)
and Granite perform the underlying storage and conversions for us. Array method like .includes?(value)
would by extension work.
What are your thoughts on this?
We talked about this on Gitter. Granite currently supports array if the underlying database driver does as well, i.e. Postgres, in the form of column values : Array(Int32)
.
This however could be documented if someone wants to make a PR.
What about including this as a fallback for MySQL?
@nsuchy You could just use a TEXT column with a JSON converter. I.e.
column details : Array(Int32), column_type: "TEXT", converter: Granite::Converters::Json(Array(Int32), String)
Which would save the array as JSON like "[1,2,3]"
, then read it from the JSON string as a Array(Int32)
.