These are chat archives for ramda/ramda

11th
Mar 2016
Julien Goux
@jgoux
Mar 11 2016 08:53
Hello
What would be an efficient way to build a SQL string "where" clause based on a queryString object ?
It starts from something like : { filter1: "thing", filter2: "foo", filter3: "bar"}, and the computation needs to produce : ["column1 = ${filter1} AND column2 < ${filter2} AND column3 != ${filter3}", filters]
reduce is definitly the key, but I'm not sure about joining string at each iteration
Raine Virta
@raine
Mar 11 2016 09:36
nice. github got reactions
to issues and their comments
Keith Alexander
@kwijibo
Mar 11 2016 09:40
@jgoux what about something like pipe( toPairs, map(filterPairToSql), join(' AND ') )
Raine Virta
@raine
Mar 11 2016 09:41
not an expert, but is it safe to construct SQL queries "manually" like this?
Keith Alexander
@kwijibo
Mar 11 2016 09:52
give me parameterized SQL or give me death?
Stefano Vozza
@svozza
Mar 11 2016 09:53
little bobby tables
Keith Alexander
@kwijibo
Mar 11 2016 09:54
I think @jgoux is using paramerized SQL isn't he? which is why (I realised too late) he's returning a tuple, not just a concatenated string
Julien Goux
@jgoux
Mar 11 2016 09:55
@raine I construct a prepared query of course :D
at the moment I'll use build the string part, and consider the bindings don't need to be transformed
Keith Alexander
@kwijibo
Mar 11 2016 09:56
is filters the original filter object ?
Julien Goux
@jgoux
Mar 11 2016 09:56
I made this
const searchDemandesArchivees = (bindings) => {
  const filters = R.reduce((acc, k) =>
    R.pipe(
      R.cond([
        [R.equals("nom"), () => "data->>'patient_nom' ILIKE ${nom}"],
        [R.equals("prenom"), () => "data->>'patient_prenom' ILIKE ${prenom}"],
        [R.equals("dateDeNaissance"), () => "(data->>'patient_date_de_naissance')::date = ${dateDeNaissance}"],
        [R.equals("nodemx"), () => "data->>'numero' = ${nodemx}"],
        [R.equals("debut"), () => "(data->>'date_heure_de_creation')::date >= ${debut}"],
        [R.equals("fin"), () => "(data->>'date_heure_de_creation')::date <= ${fin}"],
        [R.T, () => acc]
      ]),
      R.append(R.__, acc)
    )(k)
  , [], R.keys(bindings))

  if (R.isEmpty(filters)) {
    return Promise.reject("Veuillez spécicier au moins un critère de recherche")
  }

  const sql = `
    SELECT *
    FROM demande_archivee
    WHERE ${R.join(" AND ", filters)}
    LIMIT 1
  `

  return db.query(sql, bindings)
}
I match a queryString parameter name to a partial where clause
any extra queryString are ignored
Julien Goux
@jgoux
Mar 11 2016 10:33
actually, I don't need to use "cond" here
I think an object : "bindingKey": "sqlClause" is all I need ^^
  const bindingsToClauses = {
    nom: "data->>'patient_nom' ILIKE ${nom}",
    prenom: "data->>'patient_prenom' ILIKE ${prenom}",
    dateDeNaissance: "(data->>'patient_date_de_naissance')::date = ${dateDeNaissance}",
    nodemx: "data->>'numero' = ${nodemx}",
    dateDeCreation: "(data->>'date_heure_de_creation')::date = ${dateDeCreation}"
  }

  const aggregateClauses = (acc, k) => R.pipe(
    R.propOr([], k),
    R.concat(acc)
  )(bindingsToClauses)

  const filters = R.pipe(
    R.reduce(aggregateClauses, []),
    R.join(" AND ")
  )(R.keys(bindings))
Keith Alexander
@kwijibo
Mar 11 2016 14:52
Can someone (@scott-christopher?) explain Future.bimap to me?
Hardy Jones
@joneshf
Mar 11 2016 14:57
@kwijibo I assume you're familiar with map.
map can only operate on a single value, in Futures case, the last type variable.
So if you have Future a b your map function ends up being (b -> c) and only affects the successful path
bimap operates on two values, the first function operates on the first type variable, the second function operates on the second type variable.
If you have a successful path, the second function is executed (much like map).
If you have a failure path, the first function is executed.
Hardy Jones
@joneshf
Mar 11 2016 15:03
Does that help?
Conor Linehan
@ConorLinehan
Mar 11 2016 16:08

Does anyone know can you merge two functions

function a(){
this.hello = () =>{console.log(‘hello')}
}

function b(){
this.goodbye = () =>{console.log(‘goodye')}
}

c = R.merge(a,b)

where c will be

function(){
this.hello;
this.goodbye
}
Hardy Jones
@joneshf
Mar 11 2016 16:13
@ConorLinehan what are you hoping to achieve? In this case c doesn't do anything, but I assume it's a simplified example.
Do you want to merge the prototypes of two objects?
Or do you want a function that invokes the two other functions?
Brad Compton (he/him)
@Bradcomp
Mar 11 2016 16:17
To be somewhat pedantic, a and b are functions, whereas hello and goodbye are methods. Is the end goal a composite object, or a function that invokes methods?
Denys Mikhalenko
@prontiol
Mar 11 2016 16:18
Not sure about this in the JavaScript case
Conor Linehan
@ConorLinehan
Mar 11 2016 16:18

@joneshf It’s a bit more domain specific. So we use a lib called ember mirage(it’s like pretender). And in that lib there’s a DSL used, and you place in a file called config.js looks like this.

import Mirage from 'ember-cli-mirage';
import Ember from 'ember';

export default function() {
  // Contacts
  this.get('/contacts');
  // this.get('/contacts', ['contacts', 'addresses']);
  this.get('/contacts/:id');
  this.post('/contacts');
  this.put('/contacts/:id');
  this.del('/contacts/:id');

  // Friends
  this.get('/friends', { coalesce: true });

  // Pets
  this.get('/pets', function({db}) {
    return { pets: db.pets.filter(pet => pet.alive) };
  });

  this.post('/pets', function({db}, req) {
    let pet = JSON.parse(req.requestBody).pet;
    if (Ember.isBlank(pet.name)) {
      let body = { errors: { name: ["can't be blank"] } };
      return new Mirage.Response(422, { some: 'header' }, body);
    } else {
      return { pet: db.pets.insert(pet) };
    }
  });

  this.put('/pets/:id', function({db}, req) {
    let pet = JSON.parse(req.requestBody).pet;
    db.pets.update(pet.id, pet);
    return pet;
  });

  this.delete('/pets/:id', function({db}, req) { }, 200);

  this.get('/word-smiths/:id');

}

Now we have multiple projects that all inherit from a base project which has common functionality between them. So we want to inherit this base config file from our base project (it’s an ember addon) and extend the routes defined here.

import baseConfig from ‘baseAddon/mirage/config’;
import Mirage from ‘mirage’;

newRoutes = function() {
    this.post(‘my-new-route’, {});
}

export default R.merge(baseConfig, newRoutes)
I should of just put up the use case my bad
Hardy Jones
@joneshf
Mar 11 2016 16:20
There's nothing wrong with trying to get the point across with a simple example first :)
Conor Linehan
@ConorLinehan
Mar 11 2016 16:22
Haha I know but it’s very domain specific I suppose :) We use ramda the same way for our local files.
import SharedTranslations from 'ember-fishtree-shared/locales/en/translations';

const Translations = {
  nav_links: {
    lessons: 'Lessons'
  }
};

export default R.mergeWith((a, b) => {
  return R.merge(a, b);
}, SharedTranslations, Translations);
Jakub Korzeniowski
@kujon
Mar 11 2016 16:27
@ConorLinehan something bleh like R.useWith(R.merge, [R.compose(R.call, R.construct), R.compose(R.call, R.construct)])?
Conor Linehan
@ConorLinehan
Mar 11 2016 16:29
Cool @kujon :) where would you put the two functions in that case?
Sorry @kujon got it now :)
Jakub Korzeniowski
@kujon
Mar 11 2016 16:34
actually, prolly easier like this; http://goo.gl/AalQHe
Keith Alexander
@kwijibo
Mar 11 2016 16:35
@joneshf Yes that explains bimap very well, thanks a lot
Conor Linehan
@ConorLinehan
Mar 11 2016 16:43
@kujon Tried it our project, think the addon expect’s a certain form so that produces function Object() { [native code] } for constructor logging where I need it to be function Function() { [native code] }
Jakub Korzeniowski
@kujon
Mar 11 2016 16:48
If it's only about the routes, why don't you create configs like: [{type: 'GET', pattern: '/myurl', callback: () => {/*do stuff*/}], ...], merge the configs and have a function which executes the config instead?
Pretty sure that’s lodash assign
So would we create POJOS merge them normally, then export something that he expects? :) How would you convert a POJO to that format? :)
Jakub Korzeniowski
@kujon
Mar 11 2016 17:00
@ConorLinehan http://goo.gl/yFxpXo or sth similar
either way, ramda is no fit for working with such APIs imho
Conor Linehan
@ConorLinehan
Mar 11 2016 17:04
Cool thanks a million @kujon :) yeah it’s a pattern used in a few other libs we use https://github.com/ember-animation/liquid-fire/blob/master/tests%2Fdummy%2Fapp%2Ftransitions.js makes it very hard to split files up though which is a pain :(
Risto Stevcev
@Risto-Stevcev
Mar 11 2016 20:07
@ConorLinehan Why not just use extends?
Denys Mikhalenko
@prontiol
Mar 11 2016 20:56
is there a function in ramda for transforming object key by key like so:
R.foo({name: 'Alice', age:30}, {age: value => value + 1, name: R.toUpper})
LeonineKing1199
@LeonineKing1199
Mar 11 2016 20:56
I think it might R.evolve()
Denys Mikhalenko
@prontiol
Mar 11 2016 20:57
yup, could not recall its name, thanks