Как сделать строку из значений многомерного массива, используя родительские дочерние значения? - Dynami c SQL генератор запросов - PullRequest
0 голосов
/ 13 января 2020

это динамические c данные массива. Я приведу ниже примерные данные из этого мне нужно сгенерировать SQL запрос

Я использую VueJs + Laravel. ниже я обновил данные и методы массива

[
  {
    "operator": "AND",
    "rules": [
      {
        "id": 100,
        "column": "dd_Tttp",
        "type": "equal",
        "value": true,

        "join": "AND",
      }
    ],
    "groups": [
      {
        "operator": "AND",
        "rules": [
          {
            "id": 200,
            "column": "dd_tering",
            "type": "equal",
            "value": true,

            "join": "AND",

          },
          {
            "id": 201,
            "column": "dd_Size",
            "type": "in",
            "value": "Standard",

            "join": "AND",

          },
          {
            "id": 202,
            "column": "dd_Lotpth",
            "type": "equal",
            "value": "12",

            "join": "AND",

          }
        ],
        "groups": [
          {
            "operator": "AND",
            "rules": [

              {
                "id": 300,
                "column": "dd_cat",
                "type": "equal",
                "value": "34",

                "join": "AND",

              },
              {
                "id": 301,
                "column": "dd_Cot",
                "type": "in",
                "value": "Coftlassic",

                "join": "AND",

              },
              {
                "id": 302,
                "column": "dd_dse",
                "type": "equal",
                "value": "2020-01-01",

                "join": "AND",

              },
              {
                "id": 303,
                "column": "dd_turflaid",
                "type": "equal",
                "value": true,

                "join": "AND",

              }
            ],
            "groups": [

            ]
          }
        ]
      }
    ]
  },
  {
    "operator": "AND",
    "rules": [

      {
        "id": 100,
        "column": "dd_get",
        "type": "equal",
        "value": true,

        "join": "AND",
      },
      {
        "id": 101,
        "column": "dd_ccc",
        "type": "in",
        "value": "Standard",

        "join": "AND",
      }
    ],
    "groups": [

    ]
  }
]

передавая данные массива выше этой функции, я хочу получить вот так

(dd_Tttp = 'true' (dd_tering = 'true' AND dd_Size IN ('Standard') AND dd_Lotpth = '12' AND (dd_cat = '34' AND dd_Cot IN ('Coftlassic') AND dd_dse = '2020-01-01' AND dd_turflaid = 'true'))) AND (dd_get = 'true' AND dd_ccc IN ('Standard'))



groupQueryGen(groups){

   let self = this;
   let join = ''; 
   let gggg = '';

  $.each(groups, function(key, group) {

        gggg = self.groupQueryGen(group.groups);
       //console.log('group',gggg);
       join = self.ruleQueryGen(group.rules);


       join += join + '( '+gggg+' )';
    });


    return join ;

}

ruleQueryGen(rules){
    let join = '';
    $.each(rules, function(index, value) {
        if(value)
        {
            if(value.type == 'equal'){
                join += value.colum+" = '"+ value.value+"' "+value.join+" ";
            }else if(value.type == 'not_equal'){
                join += value.colum+" != '"+ value.value+"' "+value.join+" ";
            }else if(value.type == 'in'){
                join += value.colum+" IN ('"+ value.value+"') "+value.join+" ";
            }else if(value.type == 'not_in'){
                join += value.colum+" NOT IN ('"+ value.value+"') "+value.join+" ";
            }else if(value.type == 'less'){
                join += value.colum+" < '"+ value.value+"' "+value.join+" ";
            }else if(value.type == 'less_or_equal'){
                join += value.colum+" <= '"+ value.value+"' "+value.join+" ";
            }else if(value.type == 'greater'){
                join += value.colum+" > '"+ value.value+"' "+value.join+" ";
            }else if(value.type == 'greater_or_equal'){
                join += value.colum+" >= '"+ value.value+"' "+value.join+" ";
            }else if(value.type == 'between'){
                join += value.colum+" BETWEEN '"+ value.value+"' AND '" + value.valueTwo+ "' "+value.join+" ";
            }else if(value.type == 'not_between'){
                join += " NOT ("+value.colum+" BETWEEN '"+ value.value+"' AND '" + value.valueTwo+"') "+value.join+" ";
            }else if(value.type == 'is_null'){
                join += value.colum+" IS NULL "+value.join+" ";
            }else if(value.type == 'is_not_null'){
                join += value.colum+" IS NOT NULL "+value.join+" ";
            }

        }

    });

    return join;

}

1 Ответ

0 голосов
/ 13 января 2020

Я бы использовал другую структуру, потому что:

  • Нет необходимости проводить различие между operator и join.
  • groups и rules действительно должны быть одним и тем же понятием. Если в нем должны быть вложенные правила, просто используйте вложенное свойство rules.
  • Когда вы используете типы in или between, свойство value действительно должно быть массивом. Парсер должен вводить запятые и другой синтаксис SQL. Не ставьте запятые внутри одной строки (хотя у вас нет таких примеров)
  • Избегайте парсинга not_between и not_is_null по отдельности; это то же самое, что between и is_null, но с NOT, примененным к нему. Это можно сделать более динамично.

Вот предлагаемая структура для вашего примера:

{
    "type": "AND",
    "rules": [{
        "id": 100,
        "column": "dd_Tttp",
        "type": "equal",
        "value": true
    }, {
        "type": "AND",
        "rules": [{
            "id": 200,
            "column": "dd_tering",
            "type": "equal",
            "value": true
        }, {
            "id": 201,
            "column": "dd_Size",
            "type": "in",
            "value": ["Standard"] // You should use arrays for type="in"
        }, {
            "id": 202,
            "column": "dd_Lotpth",
            "type": "equal",
            "value": "12"
        }, {
            "type": "AND",
            "rules": [{
                "id": 300,
                "column": "dd_cat",
                "type": "equal",
                "value": "34"
            }, {
                "id": 301,
                "column": "dd_Cot",
                "type": "in",
                "value": ["Coftlassic"]  // You should use arrays for type="in"
            }, {
                "id": 302,
                "column": "dd_dse",
                "type": "equal",
                "value": "2020-01-01"
            }, {
                "id": 303,
                "column": "dd_turflaid",
                "type": "equal",
                "value": true
            }]
        }]
    }, {
        "type": "AND",
        "rules": [{
            "id": 100,
            "column": "dd_get",
            "type": "equal",
            "value": true
        }, {
            "id": 101,
            "column": "dd_ccc",
            "type": "in",
            "value": ["Standard"] //  // You should use arrays for type="in"
        }]
    }]
};

Вот фрагмент кода, который выдает SQL из этого:

const op = { equal: " = ", not_equal: " <> ", less: " < ", less_or_equal: " <= ",
             greater: " > ", greater_or_equal: " >= " };

function toSql(rule) {
     // recursive case:
    if (rule.rules) return "(" + rule.rules.map(toSql).join("\n" + rule.type + "  ") + ")";
    // Base case (it is an atomic rule):
    if (op[rule.type]) return rule.column + op[rule.type] + JSON.stringify(rule.value); 
    // Deal with "not": that is just a negation of the opposite
    let type = rule.type.replace(/^not_/, ""); 
    let sql = rule.column + (
           type === "in" ? " IN (" + JSON.stringify(rule.value).slice(1,-1) + ")"
         : type === "between" ? " BETWEEN " + rule.value.map(item => JSON.stringify(item)).join(" AND ") 
         : type === "is_null" ? " IS NULL"
         : "<UNKNOWN TYPE:" + type + ">"
    );
    return type === rule.type ? sql : "NOT (" + sql + ")";
}

let rule = {"type": "AND","rules": [{"id": 100,"column": "dd_Tttp","type": "equal","value": true}, {"type": "AND","rules": [{"id": 200,"column": "dd_tering","type": "equal","value": true}, {"id": 201,"column": "dd_Size","type": "in","value": ["Standard"]}, {"id": 202,"column": "dd_Lotpth","type": "equal","value": "12"}, {"type": "AND","rules": [{"id": 300,"column": "dd_cat","type": "equal","value": "34"}, {"id": 301,"column": "dd_Cot","type": "in","value": ["Coftlassic"]}, {"id": 302,"column": "dd_dse","type": "equal","value": "2020-01-01"}, {"id": 303,"column": "dd_turflaid","type": "equal","value": true}]}]}, {"type": "AND","rules": [{"id": 100,"column": "dd_get","type": "equal","value": true}, {"id": 101,"column": "dd_ccc","type": "in","value": ["Standard"]}]}]};

console.log(toSql(rule));

Отключение правил

В комментарии вы добавляете требование, в котором вы хотите отключить некоторые правила. В этом случае сначала отфильтруйте правила по новому свойству disabled.

Вот тот же фрагмент с этим изменением, и где последние два (вложенные) правила отключены:

const op = { equal: " = ", not_equal: " <> ", less: " < ", less_or_equal: " <= ",
             greater: " > ", greater_or_equal: " >= " };

function toSql(rule) {
     // recursive case:
    if (rule.rules) {
        // Filter out recursive return values that are empty (using Boolean):
        let sql = rule.rules.map(toSql).filter(Boolean).join("\n" + rule.type + "  ");
        // return that SQL in parentheses, except when it is empty
        return sql ? "(" + sql + ")" : "";
    }
    // Base case (it is an atomic rule):
    if (rule.disabled) return ""; // Return empty string when disabled
    if (op[rule.type]) return rule.column + op[rule.type] + JSON.stringify(rule.value);
    // Deal with "not": that is just a negation of the opposite
    let type = rule.type.replace(/^not_/, ""); 
    let sql = rule.column + (
           type === "in" ? " IN (" + JSON.stringify(rule.value).slice(1,-1) + ")"
         : type === "between" ? " BETWEEN " + rule.value.map(item => JSON.stringify(item)).join(" AND ") 
         : type === "is_null" ? " IS NULL"
         : "<UNKNOWN TYPE:" + type + ">"
    );
    return type === rule.type ? sql : "NOT (" + sql + ")";
}

let rule = {"type": "AND","rules": [{"id": 100,"column": "dd_Tttp","type": "equal","value": true}, {"type": "AND","rules": [{"id": 200,"column": "dd_tering","type": "equal","value": true}, {"id": 201,"column": "dd_Size","type": "in","value": ["Standard"]}, {"id": 202,"column": "dd_Lotpth","type": "equal","value": "12"}, {"type": "AND","rules": [{"id": 300,"column": "dd_cat","type": "equal","value": "34"}, {"id": 301,"column": "dd_Cot","type": "in","value": ["Coftlassic"]}, {"id": 302,"column": "dd_dse","type": "equal","value": "2020-01-01"}, {"id": 303,"column": "dd_turflaid","type": "equal","value": true}]}]}, {"type": "AND","rules": [{"id": 100,disabled:true,"column": "dd_get","type": "equal","value": true}, {"id": 101,disabled:true,"column": "dd_ccc","type": "in","value": ["Standard"]}]}]};

console.log(toSql(rule));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...