I'm interested in becoming more familiar with functional programming as a paradigm, so I'm trying to introduce a more functional style to some of my projects. I'm struggling to understand how to handle side effects with a database.
I have some functions that kind of look like this:
db query
+
db query |
+ |
| v
| +--------->a()
v |
f(type)+--+
|
+--------->b()
The trouble is that both f and a are non-pure functions because they need to do database queries. I've seen some functional projects that work by having all the state in a single place and the rest of the application takes bits and pieces of state as function parameters. I can replicate something like that here by putting all the queries in f for example, but since b doesn't need the database queries used by a, this would be really inefficient.
Is there a pattern for handling database access in functional programs?
fas a parameter? In most of the cases it is not significant, especially in cases where you can load data asynchronously. – Fabio Feb 06 '21 at 19:14SELECTstatement to be a side effect, but anINSERTcertainly would. – Greg Burghardt Feb 06 '21 at 20:03SELECTstatement is often a pure function of the database, and the transaction control system prevents "side effects" from one transaction being interwoven with the processing being performed in another. – Steve Feb 06 '21 at 21:58SELECTstatement returns data from the file system, which can be updated between select statements. – Fabio Feb 06 '21 at 22:03SELECT COUNT(*) FROM MyTablereturns99. Next week, same query(with same arguments as you said)SELECT COUNT(*) FROM MyTablewill return120. With pure functionsum(12, 30)returns42today and next week it will also return42. With pure function I can save final result and never call this function anymore for arguments12and30, but I can not do it for SQL statements, I need to execute actual sql statement again. – Fabio Feb 07 '21 at 21:28MyTablerepresents 99 rows in the first case, and 120 rows in the second. It's no different from havingsum(a, b), where the values of 'a' and 'b' are changed between calls - being 12 and 30 the first time, then 40 and 55 the next week. Similarly, if you provided a literal table in the from clause (in the same way as you provided literal integers to the sum operator, and instead of providing a table reference) then the result would always be the same and could never change until the hard-coded literals were changed. – Steve Feb 07 '21 at 21:39SELECT SUM(i) FROM (VALUES (12), (30)) AS x(i). This will always return a scalar value of 42, but it does so by constructing an input table, then summing theicolumn. Similarly, aCOUNT(*)would always return a value of 2 (that being the count of rows within the table literal). These results will not change week to week, because the inputs are hard-coded. – Steve Feb 07 '21 at 21:48"SELECT COUNT(*) FROM MyTable"string to the database and receives different results at different time, which is the case for OP's example. – Fabio Feb 07 '21 at 22:31