|
7 | 7 | "source": [
|
8 | 8 | "# Getting Started with CipherStash and Jupyter Notebook\n",
|
9 | 9 | "\n",
|
10 |
| - "This notebook describes how to get started with CipherStash using Python3, Jupyter Notebook, and psycopg2.\n", |
| 10 | + "This notebook describes how to get started with CipherStash using Python3, Jupyter Notebook, psycopg2 and SQLAlchemy.and\n", |
11 | 11 | "\n",
|
12 | 12 | "## Prerequisites\n",
|
13 | 13 | "\n",
|
|
784 | 784 | " \"UPDATE examples SET encrypted_utf8_str = %s WHERE id = %s\",\n",
|
785 | 785 | " (CsText(\"UPDATED TEXT\", \"examples\", \"encrypted_utf8_str\").to_db_format(), record_id) # Replace 'column_name' and 'new_value' with actual column and value\n",
|
786 | 786 | ")\n",
|
787 |
| - "\n", |
788 | 787 | "cur.execute(\"SELECT * FROM examples WHERE id = %s\", (record_id,))\n",
|
789 | 788 | "found = cur.fetchall()[0]\n",
|
790 | 789 | "print(f\"Updated row: {CsRow(found).row}\")"
|
791 | 790 | ]
|
792 | 791 | },
|
| 792 | + { |
| 793 | + "cell_type": "markdown", |
| 794 | + "id": "e24df4fc-11c6-489e-8b6f-45faa47bab8e", |
| 795 | + "metadata": {}, |
| 796 | + "source": [ |
| 797 | + "### Roll back\n", |
| 798 | + "\n", |
| 799 | + "Free up the database connection so we can delete the table contentsup by rolling back before going to the next section:" |
| 800 | + ] |
| 801 | + }, |
| 802 | + { |
| 803 | + "cell_type": "code", |
| 804 | + "execution_count": null, |
| 805 | + "id": "f9b74fa1-430e-49d2-868c-5acff124ceb4", |
| 806 | + "metadata": {}, |
| 807 | + "outputs": [], |
| 808 | + "source": [ |
| 809 | + "conn.rollback()" |
| 810 | + ] |
| 811 | + }, |
793 | 812 | {
|
794 | 813 | "cell_type": "markdown",
|
795 | 814 | "id": "bf498c2e-00fa-4746-85b3-c4008b55003d",
|
|
813 | 832 | "outputs": [],
|
814 | 833 | "source": [
|
815 | 834 | "from cs_models import *\n",
|
| 835 | + "from datetime import date\n", |
816 | 836 | "\n",
|
817 | 837 | "# Creating engine. Optionally add echo=True to see the SQL statetments dumped to stdout\n",
|
818 | 838 | "engine = create_engine('postgresql://postgres:postgres@localhost:6432/cipherstash_getting_started')\n",
|
819 | 839 | "Session = sessionmaker(bind=engine)\n",
|
820 | 840 | "session = Session()\n",
|
821 | 841 | "\n",
|
822 |
| - "BaseModel.metadata.create_all(engine) # Create table for models if it's not created yet\n", |
| 842 | + "BaseModel.metadata.create_all(engine) # Create table for models if it's not created yetbelow and\n", |
823 | 843 | "\n",
|
824 | 844 | "session.query(Example).delete() # Clear data if there is any from previous runs\n",
|
| 845 | + "ex = Example(e_utf8_str = \"example record 1\", e_jsonb = json.dumps({'a': {'b': 1}}), e_int = 42, e_float = 3.14, e_date = date.today(), e_bool=False)\n", |
825 | 846 | "\n",
|
826 |
| - "ex = Example(utf8_str = \"example record 1\", jsonb = json.dumps({'a': {'b': 1}}))\n", |
| 847 | + "session.add(ex)\n", |
| 848 | + "session.commit()\n", |
| 849 | + "\n", |
| 850 | + "ex = Example(e_utf8_str = \"example record 2\", e_jsonb = json.dumps({'a': {'c': 2}}), e_int = 43, e_float = 1.41, e_date = date.today(), e_bool=True)\n", |
| 851 | + "session.add(ex)\n", |
| 852 | + "session.commit()\n", |
827 | 853 | "\n",
|
| 854 | + "ex3 = Example(e_utf8_str = \"example record 1\", e_jsonb = json.dumps({'a': {'b': 1}}), e_int = 44, e_float = 2.718, e_date = date.today(), e_bool=True)\n", |
828 | 855 | "session.add(ex)\n",
|
829 | 856 | "session.commit()\n",
|
830 | 857 | "\n",
|
| 858 | + "'''\n", |
| 859 | + "ex1 = Example(\n", |
| 860 | + " e_utf8_str = \"example record 1\",\n", |
| 861 | + " e_jsonb = json.dumps({'a': {'b': 1}}),\n", |
| 862 | + " e_int = 42,\n", |
| 863 | + " e_float = 3.14,\n", |
| 864 | + " e_date = date.today(),\n", |
| 865 | + " e_bool=False)\n", |
| 866 | + "\n", |
| 867 | + "ex2 = Example(\n", |
| 868 | + " e_utf8_str = \"example record 2\",\n", |
| 869 | + " e_jsonb = json.dumps({'a': {'c': 2}}),\n", |
| 870 | + " e_int = 44,\n", |
| 871 | + " e_float = 1.41,\n", |
| 872 | + " e_date = date.today(),\n", |
| 873 | + " e_bool=True)\n", |
| 874 | + "\n", |
| 875 | + "ex3 = Example(\n", |
| 876 | + " e_utf8_str = \"example record 1\",\n", |
| 877 | + " e_jsonb = json.dumps({'a': {'b': 1}}),\n", |
| 878 | + " e_int = 44,\n", |
| 879 | + " e_float = 2.718,\n", |
| 880 | + " e_date = date.today(),\n", |
| 881 | + " e_bool=True)\n", |
| 882 | + "\n", |
| 883 | + "session.add(ex1)\n", |
| 884 | + "session.add(ex2)\n", |
| 885 | + "session.add(ex3)\n", |
| 886 | + "session.commit()\n", |
| 887 | + "'''\n", |
831 | 888 | "# After the commit above, the records are visible outside of this session\n",
|
832 | 889 | "\n",
|
833 | 890 | "print(\"Example data creation done\")"
|
|
877 | 934 | "results[0].encrypted_utf8_str"
|
878 | 935 | ]
|
879 | 936 | },
|
| 937 | + { |
| 938 | + "cell_type": "markdown", |
| 939 | + "id": "1c493bdf-25fa-49ab-a5ab-87e0fbf595e5", |
| 940 | + "metadata": {}, |
| 941 | + "source": [ |
| 942 | + "### Querying by partial match\n", |
| 943 | + "\n", |
| 944 | + "Partial matching can also performed with SQLAlchemy:" |
| 945 | + ] |
| 946 | + }, |
| 947 | + { |
| 948 | + "cell_type": "code", |
| 949 | + "execution_count": null, |
| 950 | + "id": "2cfd86e9-70d2-420b-b56f-11744d5ae4bf", |
| 951 | + "metadata": {}, |
| 952 | + "outputs": [], |
| 953 | + "source": [ |
| 954 | + "# MATCH\n", |
| 955 | + "query_text = text('cs_match_v1(encrypted_utf8_str) @> cs_match_v1(:term)')\n", |
| 956 | + "query = select(Example).where(query_text).params(term=CsText(\"example record\", \"examples\", \"encrypted_utf8_str\").to_db_format())\n", |
| 957 | + "results = session.execute(query).scalars().all()\n", |
| 958 | + "\n", |
| 959 | + "for e in results:\n", |
| 960 | + " print(f\"MATCH query results: {e}\")" |
| 961 | + ] |
| 962 | + }, |
| 963 | + { |
| 964 | + "cell_type": "markdown", |
| 965 | + "id": "c35d9fd3-bfbd-4084-a00d-fee22f7e30d0", |
| 966 | + "metadata": {}, |
| 967 | + "source": [ |
| 968 | + "### Query by ORE\n", |
| 969 | + "\n", |
| 970 | + "ORE queries can be peformed too:" |
| 971 | + ] |
| 972 | + }, |
| 973 | + { |
| 974 | + "cell_type": "code", |
| 975 | + "execution_count": null, |
| 976 | + "id": "5985efb1-1944-41d6-a912-d991095bd7d8", |
| 977 | + "metadata": {}, |
| 978 | + "outputs": [], |
| 979 | + "source": [ |
| 980 | + "# ORE\n", |
| 981 | + "cur.execute(\"SELECT * FROM examples WHERE cs_ore_64_8_v1(encrypted_float) > cs_ore_64_8_v1(%s)\", (CsFloat(100.15, \"examples\", \"encrypted_float\").to_db_format(),))\n", |
| 982 | + "\n", |
| 983 | + "query_text = text('cs_ore_64_8_v1(encrypted_float) > cs_ore_64_8_v1(:term)')\n", |
| 984 | + "query = select(Example).where(query_text).params(term=CsFloat(2.0, \"examples\", \"encrypted_float\").to_db_format())\n", |
| 985 | + "results = session.execute(query).scalars().all()\n", |
| 986 | + "\n", |
| 987 | + "for e in results:\n", |
| 988 | + " print(f\"MATCH query results: {e}\")" |
| 989 | + ] |
| 990 | + }, |
880 | 991 | {
|
881 | 992 | "cell_type": "markdown",
|
882 | 993 | "id": "e93cf011-66c7-4d93-a3c8-cb6ebe4b34ff",
|
|
925 | 1036 | "metadata": {},
|
926 | 1037 | "outputs": [],
|
927 | 1038 | "source": [
|
928 |
| - "record_id = results[0].id\n", |
| 1039 | + "if len(results) > 0:\n", |
| 1040 | + " record_id = results[0].id\n", |
929 | 1041 | "\n",
|
930 |
| - "results[0].encrypted_utf8_str = 'example record 1 UPDATED'\n", |
931 |
| - "results[0].encrypted_jsonb = json.dumps({'z': {'y': 0}})\n", |
932 |
| - "session.commit()\n", |
| 1042 | + " results[0].encrypted_utf8_str = 'example record 1 UPDATED'\n", |
| 1043 | + " results[0].encrypted_jsonb = json.dumps({'z': {'y': 0}})\n", |
| 1044 | + " session.commit()\n", |
933 | 1045 | "\n",
|
934 |
| - "updated = session.query(Example).where(Example.id == record_id).first()\n", |
| 1046 | + " updated = session.query(Example).where(Example.id == record_id).first()\n", |
935 | 1047 | "\n",
|
936 |
| - "print(f\"Updated record: {updated}\")" |
| 1048 | + " print(f\"Updated record: {updated}\")\n", |
| 1049 | + "else:\n", |
| 1050 | + " print(\"Unexpected: results are empty\")" |
937 | 1051 | ]
|
938 | 1052 | },
|
939 | 1053 | {
|
|
963 | 1077 | "\n",
|
964 | 1078 | "That's all for this notebook.\n",
|
965 | 1079 | "\n",
|
966 |
| - "This notebook showed you how you can interact with CipherStash Encrypt using Python, pyscopg2, and SQLAlchemy." |
| 1080 | + "There are many more features not covered in this notebook.\n", |
| 1081 | + "Refer to [EQL repository](https://github.com/cipherstash/encrypt-query-language/) and [CipherStash documentation](https://cipherstash.com/docs) for more information." |
967 | 1082 | ]
|
968 | 1083 | }
|
969 | 1084 | ],
|
|
0 commit comments