ripgrep
datasette/datasette/views/table.py
345 if request.headers.get("content-type") != "application/json":
346 # TODO: handle form-encoded data
347 return _errors(["Invalid content-type, must be application/json"])
348 body = await request.post_body()
349 try:
350 data = json.loads(body)
351 except json.JSONDecodeError as e:
352 return _errors(["Invalid JSON: {}".format(e)])
353 if not isinstance(data, dict):
354 return _errors(["JSON must be a dictionary"])
355 keys = data.keys()
356
357 # keys must contain "row" or "rows"
358 if "row" not in keys and "rows" not in keys:
359 return _errors(['JSON must have one or other of "row" or "rows"'])
360 rows = []
361 if "row" in keys:
362 if "rows" in keys:
363 return _errors(['Cannot use "row" and "rows" at the same time'])
364 row = data["row"]
365 if not isinstance(row, dict):
366 return _errors(['"row" must be a dictionary'])
367 rows = [row]
368 data["return"] = True
370 rows = data["rows"]
371 if not isinstance(rows, list):
372 return _errors(['"rows" must be a list'])
373 for row in rows:
374 if not isinstance(row, dict):
375 return _errors(['"rows" must be a list of dictionaries'])
376
377 # Does this exceed max_insert_rows?
378 max_insert_rows = self.ds.setting("max_insert_rows")
379 if len(rows) > max_insert_rows:
380 return _errors(
381 ["Too many rows, maximum allowed is {}".format(max_insert_rows)]
382 )
389 invalid_extras = extras.keys() - valid_extras
390 if invalid_extras:
391 return _errors(
392 ['Invalid parameter: "{}"'.format('", "'.join(sorted(invalid_extras)))]
393 )
394 if extras.get("ignore") and extras.get("replace"):
395 return _errors(['Cannot use "ignore" and "replace" at the same time'])
396
397 # Validate columns of each row
417 )
418 if errors:
419 return _errors(errors)
420 return rows, errors, extras
421
424 resolved = await self.ds.resolve_table(request)
425 except NotFound as e:
426 return _error([e.args[0]], 404)
427 db = resolved.db
428 database_name = db.name
432 db = self.ds.get_database(database_name)
433 if not await db.table_exists(table_name):
434 return _error(["Table not found: {}".format(table_name)], 404)
435
436 if upsert:
444 )
445 ):
446 return _error(
447 ["Permission denied: need both insert-row and update-row"], 403
448 )
452 request.actor, "insert-row", resource=(database_name, table_name)
453 ):
454 return _error(["Permission denied"], 403)
455
456 if not db.is_mutable:
457 return _error(["Database is immutable"], 403)
458
459 pks = await db.primary_keys(table_name)
463 )
464 if errors:
465 return _error(errors, 400)
466
467 # No that we've passed pks to _validate_data it's safe to
474
475 if upsert and (ignore or replace):
476 return _error(["Upsert does not support ignore or replace"], 400)
477
478 should_return = bool(extras.get("return", False))
506 rows = await db.execute_write_fn(insert_or_upsert_rows)
507 except Exception as e:
508 return _error([str(e)])
509 result = {"ok": True}
510 if should_return:
545 resolved = await self.ds.resolve_table(request)
546 except NotFound as e:
547 return _error([e.args[0]], 404)
548 db = resolved.db
549 database_name = db.name
552 db = self.ds.get_database(database_name)
553 if not await db.table_exists(table_name):
554 return _error(["Table not found: {}".format(table_name)], 404)
555 if not await self.ds.permission_allowed(
556 request.actor, "drop-table", resource=(database_name, table_name)
557 ):
558 return _error(["Permission denied"], 403)
559 if not db.is_mutable:
560 return _error(["Database is immutable"], 403)
561 confirm = False
562 try:
datasette/datasette/views/row.py
193 await resolved.db.execute_write_fn(delete_row)
194 except Exception as e:
195 return _error([str(e)], 500)
196
197 return Response.json({"ok": True}, status=200)
215 data = json.loads(body)
216 except json.JSONDecodeError as e:
217 return _error(["Invalid JSON: {}".format(e)])
218
219 if not isinstance(data, dict):
220 return _error(["JSON must be a dictionary"])
221 if not "update" in data or not isinstance(data["update"], dict):
222 return _error(["JSON must contain an update dictionary"])
223
224 update = data["update"]
232 await resolved.db.execute_write_fn(update_row)
233 except Exception as e:
234 return _error([str(e)], 400)
235
236 result = {"ok": True}
datasette/datasette/views/database.py
792 request.actor, "create-table", resource=database_name
793 ):
794 return _error(["Permission denied"], 403)
795
796 body = await request.post_body()
798 data = json.loads(body)
799 except json.JSONDecodeError as e:
800 return _error(["Invalid JSON: {}".format(e)])
801
802 if not isinstance(data, dict):
803 return _error(["JSON must be an object"])
804
805 invalid_keys = set(data.keys()) - self._valid_keys
806 if invalid_keys:
807 return _error(["Invalid keys: {}".format(", ".join(invalid_keys))])
808
809 # ignore and replace are mutually exclusive
810 if data.get("ignore") and data.get("replace"):
811 return _error(["ignore and replace are mutually exclusive"])
812
813 # ignore and replace only allowed with row or rows
814 if "ignore" in data or "replace" in data:
815 if not data.get("row") and not data.get("rows"):
816 return _error(["ignore and replace require row or rows"])
817
818 # ignore and replace require pk or pks
819 if "ignore" in data or "replace" in data:
820 if not data.get("pk") and not data.get("pks"):
821 return _error(["ignore and replace require pk or pks"])
822
823 ignore = data.get("ignore")
829 request.actor, "update-row", resource=database_name
830 ):
831 return _error(["Permission denied - need update-row"], 403)
832
833 table_name = data.get("table")
834 if not table_name:
835 return _error(["Table is required"])
836
837 if not self._table_name_re.match(table_name):
838 return _error(["Invalid table name"])
839
840 table_exists = await db.table_exists(data["table"])
843 row = data.get("row")
844 if not columns and not rows and not row:
845 return _error(["columns, rows or row is required"])
846
847 if rows and row:
848 return _error(["Cannot specify both rows and row"])
849
850 if rows or row:
853 request.actor, "insert-row", resource=database_name
854 ):
855 return _error(["Permission denied - need insert-row"], 403)
856
857 if columns:
858 if rows or row:
859 return _error(["Cannot specify columns with rows or row"])
860 if not isinstance(columns, list):
861 return _error(["columns must be a list"])
862 for column in columns:
863 if not isinstance(column, dict):
864 return _error(["columns must be a list of objects"])
865 if not column.get("name") or not isinstance(column.get("name"), str):
866 return _error(["Column name is required"])
867 if not column.get("type"):
868 column["type"] = "text"
869 if column["type"] not in self._supported_column_types:
870 return _error(
871 ["Unsupported column type: {}".format(column["type"])]
872 )
874 dupes = {c["name"] for c in columns if columns.count(c) > 1}
875 if dupes:
876 return _error(["Duplicate column name: {}".format(", ".join(dupes))])
877
878 if row:
881 if rows:
882 if not isinstance(rows, list):
883 return _error(["rows must be a list"])
884 for row in rows:
885 if not isinstance(row, dict):
886 return _error(["rows must be a list of objects"])
887
888 pk = data.get("pk")
890
891 if pk and pks:
892 return _error(["Cannot specify both pk and pks"])
893 if pk:
894 if not isinstance(pk, str):
895 return _error(["pk must be a string"])
896 if pks:
897 if not isinstance(pks, list):
898 return _error(["pks must be a list"])
899 for pk in pks:
900 if not isinstance(pk, str):
901 return _error(["pks must be a list of strings"])
902
903 # If table exists already, read pks from that instead
915 bad_pks = True
916 if bad_pks:
917 return _error(["pk cannot be changed for existing table"])
918 pks = actual_pks
919
932 schema = await db.execute_write_fn(create_table)
933 except Exception as e:
934 return _error([str(e)])
935 table_url = self.ds.absolute_url(
936 request, self.ds.urls.table(db.name, table_name)