gencow 0.1.107 → 0.1.108

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/index.js CHANGED
@@ -1904,12 +1904,77 @@ function createRlsDb(db, userId) {
1904
1904
  }
1905
1905
 
1906
1906
  // ../core/src/crud.ts
1907
- import { eq, desc, asc, ilike, or, and, count as drizzleCount, getTableName } from "drizzle-orm";
1907
+ import { eq, ne, gt, gte, lt, lte, desc, asc, like, ilike, inArray, notInArray, or, and, count as drizzleCount, getTableName } from "drizzle-orm";
1908
1908
  function detectIdType(column) {
1909
1909
  const colType = column.dataType;
1910
1910
  if (colType === "string") return v.string();
1911
1911
  return v.number();
1912
1912
  }
1913
+ var MAX_FILTER_DEPTH = 5;
1914
+ var FILTER_OPS = ["eq", "ne", "gt", "gte", "lt", "lte", "in", "nin", "like", "ilike"];
1915
+ function isValidFilterOp(op) {
1916
+ return FILTER_OPS.includes(op);
1917
+ }
1918
+ function applyFilterOp(col, op, value) {
1919
+ switch (op) {
1920
+ case "eq":
1921
+ return eq(col, value);
1922
+ case "ne":
1923
+ return ne(col, value);
1924
+ case "gt":
1925
+ return gt(col, value);
1926
+ case "gte":
1927
+ return gte(col, value);
1928
+ case "lt":
1929
+ return lt(col, value);
1930
+ case "lte":
1931
+ return lte(col, value);
1932
+ case "in":
1933
+ if (!Array.isArray(value) || value.length === 0) return void 0;
1934
+ return inArray(col, value);
1935
+ case "nin":
1936
+ if (!Array.isArray(value) || value.length === 0) return void 0;
1937
+ return notInArray(col, value);
1938
+ case "like":
1939
+ if (typeof value !== "string") return void 0;
1940
+ return like(col, value);
1941
+ case "ilike":
1942
+ if (typeof value !== "string") return void 0;
1943
+ return ilike(col, value);
1944
+ default:
1945
+ return void 0;
1946
+ }
1947
+ }
1948
+ function parseFilterNode(node, table, allowedFields, depth = 0) {
1949
+ if (depth > MAX_FILTER_DEPTH) return void 0;
1950
+ const conditions = [];
1951
+ for (const [key, val] of Object.entries(node)) {
1952
+ if (key === "OR") {
1953
+ if (!Array.isArray(val)) continue;
1954
+ const orConds = val.filter((child) => child != null && typeof child === "object" && !Array.isArray(child)).map((child) => parseFilterNode(child, table, allowedFields, depth + 1)).filter((c) => c !== void 0);
1955
+ if (orConds.length > 0) conditions.push(or(...orConds));
1956
+ continue;
1957
+ }
1958
+ if (key === "AND") {
1959
+ if (!Array.isArray(val)) continue;
1960
+ const andConds = val.filter((child) => child != null && typeof child === "object" && !Array.isArray(child)).map((child) => parseFilterNode(child, table, allowedFields, depth + 1)).filter((c) => c !== void 0);
1961
+ if (andConds.length > 0) conditions.push(and(...andConds));
1962
+ continue;
1963
+ }
1964
+ if (allowedFields && !allowedFields.includes(key)) continue;
1965
+ const col = table[key];
1966
+ if (!col) continue;
1967
+ if (val != null && typeof val === "object" && !Array.isArray(val) && "op" in val) {
1968
+ const { op, value } = val;
1969
+ if (!isValidFilterOp(op)) continue;
1970
+ const cond = applyFilterOp(col, op, value);
1971
+ if (cond) conditions.push(cond);
1972
+ continue;
1973
+ }
1974
+ conditions.push(eq(col, val));
1975
+ }
1976
+ return conditions.length > 0 ? and(...conditions) : void 0;
1977
+ }
1913
1978
  function crud(table, options) {
1914
1979
  const anyTable = table;
1915
1980
  const tableName = getTableName(table);
@@ -1938,12 +2003,14 @@ function crud(table, options) {
1938
2003
  );
1939
2004
  conditions.push(or(...searchConds));
1940
2005
  }
1941
- if (args?.filters && options?.allowedFilters?.length) {
1942
- for (const [key, value] of Object.entries(args.filters)) {
1943
- if (options.allowedFilters.includes(key) && anyTable[key]) {
1944
- conditions.push(eq(anyTable[key], value));
1945
- }
1946
- }
2006
+ if (args?.filters && typeof args.filters === "object" && options?.allowedFilters?.length) {
2007
+ const allowedFields = options.allowedFilters;
2008
+ const filterCondition = parseFilterNode(
2009
+ args.filters,
2010
+ anyTable,
2011
+ allowedFields
2012
+ );
2013
+ if (filterCondition) conditions.push(filterCondition);
1947
2014
  }
1948
2015
  return conditions.length > 0 ? and(...conditions) : void 0;
1949
2016
  }
@@ -2067,6 +2134,7 @@ function crud(table, options) {
2067
2134
  }
2068
2135
  export {
2069
2136
  GencowValidationError,
2137
+ applyFilterOp,
2070
2138
  buildRealtimeCtx,
2071
2139
  createRlsDb,
2072
2140
  createScheduler,
@@ -2087,6 +2155,7 @@ export {
2087
2155
  mutation,
2088
2156
  ownerRls,
2089
2157
  parseArgs,
2158
+ parseFilterNode,
2090
2159
  query,
2091
2160
  registerClient,
2092
2161
  subscribe,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gencow",
3
- "version": "0.1.107",
3
+ "version": "0.1.108",
4
4
  "description": "Gencow — AI Backend Engine",
5
5
  "type": "module",
6
6
  "bin": {
package/server/index.js CHANGED
@@ -1955,12 +1955,75 @@ var init_rls_db = __esm({
1955
1955
  });
1956
1956
 
1957
1957
  // ../core/src/crud.ts
1958
- import { eq, desc, asc, ilike, or, and, count as drizzleCount, getTableName } from "drizzle-orm";
1958
+ import { eq, ne, gt, gte, lt, lte, desc, asc, like, ilike, inArray, notInArray, or, and, count as drizzleCount, getTableName } from "drizzle-orm";
1959
1959
  function detectIdType(column) {
1960
1960
  const colType = column.dataType;
1961
1961
  if (colType === "string") return v.string();
1962
1962
  return v.number();
1963
1963
  }
1964
+ function isValidFilterOp(op) {
1965
+ return FILTER_OPS.includes(op);
1966
+ }
1967
+ function applyFilterOp(col, op, value) {
1968
+ switch (op) {
1969
+ case "eq":
1970
+ return eq(col, value);
1971
+ case "ne":
1972
+ return ne(col, value);
1973
+ case "gt":
1974
+ return gt(col, value);
1975
+ case "gte":
1976
+ return gte(col, value);
1977
+ case "lt":
1978
+ return lt(col, value);
1979
+ case "lte":
1980
+ return lte(col, value);
1981
+ case "in":
1982
+ if (!Array.isArray(value) || value.length === 0) return void 0;
1983
+ return inArray(col, value);
1984
+ case "nin":
1985
+ if (!Array.isArray(value) || value.length === 0) return void 0;
1986
+ return notInArray(col, value);
1987
+ case "like":
1988
+ if (typeof value !== "string") return void 0;
1989
+ return like(col, value);
1990
+ case "ilike":
1991
+ if (typeof value !== "string") return void 0;
1992
+ return ilike(col, value);
1993
+ default:
1994
+ return void 0;
1995
+ }
1996
+ }
1997
+ function parseFilterNode(node, table, allowedFields, depth = 0) {
1998
+ if (depth > MAX_FILTER_DEPTH) return void 0;
1999
+ const conditions = [];
2000
+ for (const [key, val] of Object.entries(node)) {
2001
+ if (key === "OR") {
2002
+ if (!Array.isArray(val)) continue;
2003
+ const orConds = val.filter((child) => child != null && typeof child === "object" && !Array.isArray(child)).map((child) => parseFilterNode(child, table, allowedFields, depth + 1)).filter((c) => c !== void 0);
2004
+ if (orConds.length > 0) conditions.push(or(...orConds));
2005
+ continue;
2006
+ }
2007
+ if (key === "AND") {
2008
+ if (!Array.isArray(val)) continue;
2009
+ const andConds = val.filter((child) => child != null && typeof child === "object" && !Array.isArray(child)).map((child) => parseFilterNode(child, table, allowedFields, depth + 1)).filter((c) => c !== void 0);
2010
+ if (andConds.length > 0) conditions.push(and(...andConds));
2011
+ continue;
2012
+ }
2013
+ if (allowedFields && !allowedFields.includes(key)) continue;
2014
+ const col = table[key];
2015
+ if (!col) continue;
2016
+ if (val != null && typeof val === "object" && !Array.isArray(val) && "op" in val) {
2017
+ const { op, value } = val;
2018
+ if (!isValidFilterOp(op)) continue;
2019
+ const cond = applyFilterOp(col, op, value);
2020
+ if (cond) conditions.push(cond);
2021
+ continue;
2022
+ }
2023
+ conditions.push(eq(col, val));
2024
+ }
2025
+ return conditions.length > 0 ? and(...conditions) : void 0;
2026
+ }
1964
2027
  function crud(table, options) {
1965
2028
  const anyTable = table;
1966
2029
  const tableName = getTableName(table);
@@ -1989,12 +2052,14 @@ function crud(table, options) {
1989
2052
  );
1990
2053
  conditions.push(or(...searchConds));
1991
2054
  }
1992
- if (args?.filters && options?.allowedFilters?.length) {
1993
- for (const [key, value] of Object.entries(args.filters)) {
1994
- if (options.allowedFilters.includes(key) && anyTable[key]) {
1995
- conditions.push(eq(anyTable[key], value));
1996
- }
1997
- }
2055
+ if (args?.filters && typeof args.filters === "object" && options?.allowedFilters?.length) {
2056
+ const allowedFields = options.allowedFilters;
2057
+ const filterCondition = parseFilterNode(
2058
+ args.filters,
2059
+ anyTable,
2060
+ allowedFields
2061
+ );
2062
+ if (filterCondition) conditions.push(filterCondition);
1998
2063
  }
1999
2064
  return conditions.length > 0 ? and(...conditions) : void 0;
2000
2065
  }
@@ -2116,11 +2181,14 @@ function crud(table, options) {
2116
2181
  remove: removeDef
2117
2182
  };
2118
2183
  }
2184
+ var MAX_FILTER_DEPTH, FILTER_OPS;
2119
2185
  var init_crud = __esm({
2120
2186
  "../core/src/crud.ts"() {
2121
2187
  "use strict";
2122
2188
  init_reactive();
2123
2189
  init_v();
2190
+ MAX_FILTER_DEPTH = 5;
2191
+ FILTER_OPS = ["eq", "ne", "gt", "gte", "lt", "lte", "in", "nin", "like", "ilike"];
2124
2192
  }
2125
2193
  });
2126
2194
 
@@ -2128,6 +2196,7 @@ var init_crud = __esm({
2128
2196
  var src_exports = {};
2129
2197
  __export(src_exports, {
2130
2198
  GencowValidationError: () => GencowValidationError,
2199
+ applyFilterOp: () => applyFilterOp,
2131
2200
  buildRealtimeCtx: () => buildRealtimeCtx,
2132
2201
  createRlsDb: () => createRlsDb,
2133
2202
  createScheduler: () => createScheduler,
@@ -2148,6 +2217,7 @@ __export(src_exports, {
2148
2217
  mutation: () => mutation,
2149
2218
  ownerRls: () => ownerRls,
2150
2219
  parseArgs: () => parseArgs,
2220
+ parseFilterNode: () => parseFilterNode,
2151
2221
  query: () => query,
2152
2222
  registerClient: () => registerClient,
2153
2223
  subscribe: () => subscribe,