import {
  AbstractQuery,
  ExpressionBuilder,
  clientToServer,
  defaultFormat,
  newQuery,
  newQuerySymbol
} from "./chunk-2OFTKN5C.js";
import {
  mapCondition,
  toStaticParam
} from "./chunk-OZZJ3HSP.js";
import {
  assert
} from "./chunk-EZM3XBAB.js";

// ../zero-schema/src/builder/relationship-builder.ts
function relationships(table2, cb) {
  const relationships2 = cb({ many, one });
  return {
    name: table2.schema.name,
    relationships: relationships2
  };
}
function many(...args) {
  return args.map((arg) => ({
    sourceField: arg.sourceField,
    destField: arg.destField,
    destSchema: arg.destSchema.schema.name,
    cardinality: "many"
  }));
}
function one(...args) {
  return args.map((arg) => ({
    sourceField: arg.sourceField,
    destField: arg.destField,
    destSchema: arg.destSchema.schema.name,
    cardinality: "one"
  }));
}

// ../zql/src/query/static-query.ts
var StaticQuery = class _StaticQuery extends AbstractQuery {
  constructor(schema, tableName, ast, format, system = "permissions", customQueryID, currentJunction) {
    super(
      void 0,
      schema,
      tableName,
      ast,
      format,
      system,
      customQueryID,
      currentJunction
    );
  }
  expressionBuilder() {
    return new ExpressionBuilder(this._exists);
  }
  [newQuerySymbol](_delegate, schema, tableName, ast, format, customQueryID, currentJunction) {
    return new _StaticQuery(
      schema,
      tableName,
      ast,
      format,
      "permissions",
      customQueryID,
      currentJunction
    );
  }
  get ast() {
    return this._completeAst();
  }
  materialize() {
    throw new Error("StaticQuery cannot be materialized");
  }
  run() {
    return Promise.reject(new Error("StaticQuery cannot be run"));
  }
  preload() {
    throw new Error("StaticQuery cannot be preloaded");
  }
};

// ../zero-schema/src/permissions.ts
var ANYONE_CAN = [
  (_, eb) => eb.and()
];
var ANYONE_CAN_DO_ANYTHING = {
  row: {
    select: ANYONE_CAN,
    insert: ANYONE_CAN,
    update: {
      preMutation: ANYONE_CAN,
      postMutation: ANYONE_CAN
    },
    delete: ANYONE_CAN
  }
};
var NOBODY_CAN = [];
async function definePermissions(schema, definer) {
  const expressionBuilders = {};
  for (const name of Object.keys(schema.tables)) {
    expressionBuilders[name] = new StaticQuery(
      schema,
      name,
      { table: name },
      defaultFormat
    ).expressionBuilder();
  }
  const config = await definer();
  return compilePermissions(schema, config, expressionBuilders);
}
function compilePermissions(schema, authz, expressionBuilders) {
  if (!authz) {
    return void 0;
  }
  const nameMapper = clientToServer(schema.tables);
  const ret = { tables: {} };
  for (const [tableName, tableConfig] of Object.entries(authz)) {
    const serverName = schema.tables[tableName].serverName ?? tableName;
    ret.tables[serverName] = {
      row: compileRowConfig(
        nameMapper,
        tableName,
        tableConfig.row,
        expressionBuilders[tableName]
      ),
      cell: compileCellConfig(
        nameMapper,
        tableName,
        tableConfig.cell,
        expressionBuilders[tableName]
      )
    };
  }
  return ret;
}
function compileRowConfig(clientToServer2, tableName, rowRules, expressionBuilder) {
  if (!rowRules) {
    return void 0;
  }
  return {
    select: compileRules(
      clientToServer2,
      tableName,
      rowRules.select,
      expressionBuilder
    ),
    insert: compileRules(
      clientToServer2,
      tableName,
      rowRules.insert,
      expressionBuilder
    ),
    update: {
      preMutation: compileRules(
        clientToServer2,
        tableName,
        rowRules.update?.preMutation,
        expressionBuilder
      ),
      postMutation: compileRules(
        clientToServer2,
        tableName,
        rowRules.update?.postMutation,
        expressionBuilder
      )
    },
    delete: compileRules(
      clientToServer2,
      tableName,
      rowRules.delete,
      expressionBuilder
    )
  };
}
function compileRules(clientToServer2, tableName, rules, expressionBuilder) {
  if (!rules) {
    return void 0;
  }
  return rules.map((rule) => {
    const cond = rule(authDataRef, expressionBuilder);
    return ["allow", mapCondition(cond, tableName, clientToServer2)];
  });
}
function compileCellConfig(clientToServer2, tableName, cellRules, expressionBuilder) {
  if (!cellRules) {
    return void 0;
  }
  const ret = {};
  for (const [columnName, rules] of Object.entries(cellRules)) {
    ret[columnName] = {
      select: compileRules(
        clientToServer2,
        tableName,
        rules.select,
        expressionBuilder
      ),
      insert: compileRules(
        clientToServer2,
        tableName,
        rules.insert,
        expressionBuilder
      ),
      update: {
        preMutation: compileRules(
          clientToServer2,
          tableName,
          rules.update?.preMutation,
          expressionBuilder
        ),
        postMutation: compileRules(
          clientToServer2,
          tableName,
          rules.update?.postMutation,
          expressionBuilder
        )
      },
      delete: compileRules(
        clientToServer2,
        tableName,
        rules.delete,
        expressionBuilder
      )
    };
  }
  return ret;
}
var CallTracker = class _CallTracker {
  #anchor;
  #path;
  constructor(anchor, path) {
    this.#anchor = anchor;
    this.#path = path;
  }
  get(target, prop) {
    if (prop === toStaticParam) {
      return target[toStaticParam];
    }
    assert(typeof prop === "string");
    const path = [...this.#path, prop];
    return new Proxy(
      {
        [toStaticParam]: () => staticParam(this.#anchor, path)
      },
      new _CallTracker(this.#anchor, path)
    );
  }
};
function baseTracker(anchor) {
  return new Proxy(
    {
      [toStaticParam]: () => {
        throw new Error("no JWT field specified");
      }
    },
    new CallTracker(anchor, [])
  );
}
var authDataRef = baseTracker("authData");
var preMutationRowRef = baseTracker("preMutationRow");
function staticParam(anchorClass, field) {
  return {
    type: "static",
    anchor: anchorClass,
    // for backwards compatibility
    field: field.length === 1 ? field[0] : field
  };
}

// ../zql/src/query/escape-like.ts
function escapeLike(val) {
  return val.replace(/[%_]/g, "\\$&");
}

// ../zql/src/query/named.ts
function normalizeParser(parser) {
  if (parser) {
    if ("parse" in parser) {
      return parser.parse.bind(parser);
    }
    return parser;
  }
  return void 0;
}
function syncedQuery(name, parser, fn) {
  const impl = syncedQueryImpl(name, fn, false);
  const ret = (...args) => impl(void 0, args);
  ret.queryName = name;
  ret.parse = normalizeParser(parser);
  ret.takesContext = false;
  return ret;
}
function syncedQueryWithContext(name, parser, fn) {
  const impl = syncedQueryImpl(name, fn, true);
  const ret = (context, ...args) => impl(context, args);
  ret.queryName = name;
  ret.parse = normalizeParser(parser);
  ret.takesContext = true;
  return ret;
}
function syncedQueryImpl(name, fn, takesContext) {
  return (context, args) => {
    const q = takesContext ? fn(context, ...args) : fn(...args);
    return q.nameAndArgs(name, args);
  };
}
function withValidation(fn) {
  if (!fn.parse) {
    throw new Error("ret does not have a parse function defined");
  }
  const ret = (context, ...args) => {
    const f = fn;
    const parsed = f.parse(args);
    return f.takesContext ? f(context, ...parsed) : f(...parsed);
  };
  ret.queryName = fn.queryName;
  ret.parse = fn.parse;
  ret.takesContext = true;
  return ret;
}
function createBuilder(s) {
  return makeQueryBuilders(s);
}
function makeQueryBuilders(schema) {
  return new Proxy(
    {},
    {
      get: (target, prop) => {
        if (prop in target) {
          return target[prop];
        }
        if (!(prop in schema.tables)) {
          throw new Error(`Table ${prop} does not exist in schema`);
        }
        const q = newQuery(void 0, schema, prop);
        target[prop] = q;
        return q;
      }
    }
  );
}

export {
  relationships,
  ANYONE_CAN,
  ANYONE_CAN_DO_ANYTHING,
  NOBODY_CAN,
  definePermissions,
  escapeLike,
  syncedQuery,
  syncedQueryWithContext,
  withValidation,
  createBuilder
};
//# sourceMappingURL=chunk-GD6ERDZU.js.map
