문맥 자유 문법은 일반적으로 구조와 같은 트리를 가지며 기능적 프로그램 역시 구조와 같은 트리 구조를 가지고 있습니다. 나는 다음과 같은 것이 당신의 모든 문제를 해결할 것이라고 주장하지 않지만, SQLite3
과 같은 것을 사용하고 싶지 않다면 그것은 방향의 좋은 단계입니다.
from functools import partial
def select_keys(keys, from_):
return ({k : fun(v, row) for k, (v, fun) in keys.items()}
for row in from_)
def select_where(from_, where):
return (row for row in from_
if where(row))
def default_keys_transform(keys, transform=lambda v, row: row[v]):
return {k : (k, transform) for k in keys}
def select(keys=None, from_=None, where=None):
"""
SELECT v1 AS k1, 2*v2 AS k2 FROM table WHERE v1 = a AND v2 >= b OR v3 = c
translates to
select(dict(k1=(v1, lambda v1, r: r[v1]), k2=(v2, lambda v2, r: 2*r[v2])
, from_=table
, where= lambda r : r[v1] = a and r[v2] >= b or r[v3] = c)
"""
assert from_ is not None
idfunc = lambda k, t : t
select_k = idfunc if keys is None else select_keys
if isinstance(keys, list):
keys = default_keys_transform(keys)
idfunc = lambda t, w : t
select_w = idfunc if where is None else select_where
return select_k(keys, select_w(from_, where))
사용자가 임의 코드를 실행할 수있는 능력을 부여하지 않았 음을 어떻게 확신합니까? 이 프레임 워크는 가능한 모든 기능을 허용합니다. 자, 수용 가능한 함수 오브젝트의 고정 된 목록을 노출시키는 보안을 위해 랩퍼 위에 그 래퍼를 올릴 수 있습니다.
ALLOWED_FUNCS = [ operator.mul, operator.add, ...] # List of allowed funcs
def select_secure(keys=None, from_=None, where=None):
if keys is not None and isinstance(keys, dict):
for v, fun keys.values:
assert fun in ALLOWED_FUNCS
if where is not None:
assert_composition_of_allowed_funcs(where, ALLOWED_FUNCS)
return select(keys=keys, from_=from_, where=where)
작성 방법 assert_composition_of_allowed_funcs
. 파이썬에서는 그렇게하기가 어렵지만, 리스프에서는 쉽습니다. 어디에서 lips와 같은 형식으로 평가할 함수 목록이 있습니까? 예 : where=(operator.add, (operator.getitem, row, v1), 2)
또는 where=(operator.mul, (operator.add, (opreator.getitem, row, v2), 2), 3)
.
이렇게하면 where 기능이 ALLOWED_FUNCS 또는 float, int, str과 같은 상수로만 구성되도록 apply_lisp
함수를 작성할 수 있습니다.
def apply_lisp(where, rowsym, rowval, ALLOWED_FUNCS):
assert where[0] in ALLOWED_FUNCS
return apply(where[0],
[ (apply_lisp(w, rowsym, rowval, ALLOWED_FUNCS)
if isinstance(w, tuple)
else rowval if w is rowsym
else w if isinstance(w, (float, int, str))
else None) for w in where[1:] ])
또한 유형을 재정의하지 않으므로 정확한 유형을 확인해야합니다. 따라서 isinstance
을 사용하지 말고 type in (float, int, str)
을 사용하십시오. 프로그래밍의
Greenspun의 열 번째 규칙 : 오 소년 우리는에 실행 한 모든 충분히 복잡한 C 나 포트란 프로그램은 커먼 리스프의 절반의 임시 비공식적으로 지정 버그 쟁이 느린 구현이 포함되어 있습니다.
App Engine에 GQL을 구현 했습니까? : P – wTyeRogers