@elumixor/notion-orm 0.1.1

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/README.md ADDED
@@ -0,0 +1,267 @@
1
+ # Notion ORM
2
+
3
+ ⚠️ This package is Still in development 🏗️
4
+
5
+ A library to simplify adding and querying [Notion](https://notion.so/product) databases/tables. Giving typeahead/intellisense support on columns and expected column values on user specified databases. Built on top of [Notion API](https://developers.notion.com/)
6
+
7
+ Databases with the following column types are supported:
8
+
9
+ - Multi-select
10
+ - Select
11
+ - Status
12
+ - Date
13
+ - Text
14
+ - Url
15
+ - Checkbox
16
+ - Email
17
+ - Phone Number
18
+
19
+ ## Installation
20
+
21
+ The only requirement is a Notion Developer API key ([here](https://developers.notion.com/)) and database IDs you want. Be sure to connect your [integration](https://developers.notion.com/docs/working-with-databases#adding-pages-to-a-database) (🚧 *Permissions* section) with your tables
22
+
23
+ ```bash
24
+ npm install @haustle/notion-orm --save-dev
25
+ ```
26
+
27
+ At the root of your project run the CLI to scaffold a config file (defaults to JavaScript unless a `tsconfig.json` is present):
28
+
29
+ ```bash
30
+ npx notion init
31
+ # or
32
+ bun notion init
33
+ ```
34
+
35
+ You can force a specific format with `--js` or `--ts`. You’ll need to pass your developer key and database IDs. How to get database IDs [here](https://developers.notion.com/docs/working-with-databases#adding-pages-to-a-database)
36
+
37
+ ```tsx
38
+ // notion.config.ts (generated with `notion init --ts`)
39
+
40
+ // Be sure to create a .env.local file and add your NOTION_KEY
41
+
42
+ // If you don't have an API key, sign up for free
43
+ // [here](https://developers.notion.com)
44
+
45
+ const auth = process.env.NOTION_KEY || "your-notion-api-key-here";
46
+ const NotionConfig = {
47
+ auth,
48
+ databaseIds: [
49
+ // Add undashed database source IDs here (ex. "2a3c495da03c80bc99fe000bbf2be4bb")
50
+ // or use the following command to automatically update
51
+ // `notion add <database-source-id or URL>`
52
+ // If you decide to manually add database IDs, be sure to run
53
+ // `notion generate` to properly update the local database types
54
+ ],
55
+ };
56
+
57
+ export default NotionConfig;
58
+ ```
59
+
60
+ Execute the following command from the root project directory.
61
+
62
+ ```bash
63
+ npx notion generate
64
+ ```
65
+
66
+ **Package Size**
67
+ Unpackaged size is 70.6KB and the installation size is 5.12MB (5.03MB from `@notionhq/client` dependency)
68
+
69
+ ## Implementation
70
+
71
+ Databases can be imported via barrel file or from the individual database file. All database names will be camelCase 🐫.
72
+
73
+ ```tsx
74
+ // Barrel Import (access to all databases)
75
+ import * as notion from "@haustle/notion-orm";
76
+ notion.databaseName.add();
77
+ notion.databaseName2.query();
78
+ ```
79
+
80
+ ```jsx
81
+ // Individual Database Import
82
+ import {
83
+ databaseName,
84
+ DatabaseSchemaType,
85
+ QuerySchemaType,
86
+ } from "@haustle/notion-orm/build/db/databaseName";
87
+
88
+ databaseName.add();
89
+ ```
90
+
91
+ - `DatabaseSchemaType`: Object type accepted in the database’s `add()` function
92
+ - `QuerySchemaType`: Object type accepted in the database’s `query()` function
93
+
94
+ The following examples for querying & adding are for server-side calls. If you’re looking to use this framework to execute client-side calls (ex. button click add/query X) visit the [Client (React)](https://www.notion.so/Notion-ORM-README-fdd30271bf944a3e85cb999ec8d5447d) section after reading
95
+
96
+ **Adding**
97
+
98
+ Only required column required is the title.
99
+
100
+ ```jsx
101
+ notion.books.add({
102
+ bookName: "Raphael, Painter in Rome: a Novel", // title
103
+ author: "Stephanie Storey", // text
104
+ status: "In progress", // status
105
+ numberOfPages: 307, // number
106
+ genre: ["Historical Fiction"], // multi-select
107
+ rating: "⭐️⭐️⭐️⭐️", // select
108
+ startDate: {
109
+ // date
110
+ start: "2023-01-01",
111
+ },
112
+ phone: "0000000000", // phone
113
+ email: "tyrus@haustle.studio", // email
114
+ });
115
+ ```
116
+
117
+ All column types in Notion databases are mapped to a typescript type.
118
+
119
+ | Column Type | Object |
120
+ | ------------ | -------------- |
121
+ | Title | string |
122
+ | Text | string |
123
+ | Select | string |
124
+ | Multi-select | Array (string) |
125
+ | Status | string |
126
+ | Number | number |
127
+ | Date | Object |
128
+ | Phone number | string |
129
+ | Email | string |
130
+
131
+ **Querying**
132
+
133
+ For each column type you’ll be presented with the available querying filter. Find all filter conditions [here](https://developers.notion.com/reference/post-database-query-filter)
134
+
135
+ While the querying functionality works, it’s **not complete and there is room for user error**. For instance, the `filter` object should contain one child. Either the column name (signifies single filter), or `and` or `or` (signify compound filters). However there is no typecheck in place to stop adding multiple children
136
+
137
+ Unlike `add()` , there is no transformation after the inputted object. So the querying object you’re creating is exactly what you’d normally use to query the Notion API. Learn more about them [here](https://developers.notion.com/reference/post-database-query-filter)
138
+
139
+ Example of a single filter
140
+
141
+ ```tsx
142
+ notion.books.query({
143
+ filter: {
144
+ genre: {
145
+ contains: "Sci-Fi",
146
+ },
147
+ },
148
+ sort: [
149
+ {
150
+ property: "name",
151
+ direction: "ascending",
152
+ },
153
+ {
154
+ property: "Author name",
155
+ direction: "ascending",
156
+ },
157
+ ],
158
+ });
159
+ ```
160
+
161
+ Example of compound filters, which is signified with `and` and `or`. You can nest these are far as you want (i.e `and` filters within `or` filter). Learn more [here](https://developers.notion.com/reference/post-database-query-filter#compound-filter-object)
162
+
163
+ ```tsx
164
+ await notion.books.query({
165
+ filter: {
166
+ or: [
167
+ {
168
+ genre: {
169
+ contains: "Sci-Fi",
170
+ },
171
+ },
172
+ {
173
+ genre: {
174
+ contains: "Biography",
175
+ },
176
+ },
177
+ ],
178
+ },
179
+ });
180
+ ```
181
+
182
+ Down below is what’s returned on a successful response. `results` being a simplified extracted version of the `rawResponse` (response from Notion API)
183
+
184
+ ```tsx
185
+ {
186
+ rawResponse: { /* Whatever Notion API returns */},
187
+ results: [
188
+ {
189
+ bookName: "How to Change Your Mind",
190
+ genre: ["Non-fiction"],
191
+ numberPages: 460,
192
+ rating: "⭐️⭐️⭐️⭐️"
193
+ },
194
+ ]
195
+ }
196
+ ```
197
+
198
+ ## Client-side (React)
199
+
200
+ Notion API currently blocks calls from browser (per CORS)
201
+
202
+ You can get around this by creating API endpoints on stack of your choice. I’ve provided examples only for **Next.js**, but the high level implementation should work with any backend.
203
+
204
+ If you’re planning to only make server-side calls to your Notion database (from `GetStaticProps` or `GetServerSideProps`). These calls work totally fine, as these functions are executed server-side before page load. So you can ignore the proceeding steps
205
+
206
+ ```tsx
207
+ export const getStaticProps: GetStaticProps = async () => {
208
+ const response = await NotionClient.books.query({
209
+ filter: {
210
+ genre: {
211
+ is_not_empty: true,
212
+ },
213
+ },
214
+ });
215
+ return {
216
+ props: {
217
+ apiResponse: response
218
+ }
219
+ }
220
+ ```
221
+
222
+ To execute calls client-side (ex. on button click) an API endpoint is needed to get around CORS. In this example we’re passing the databases `DatabaseSchemaType` as the body of the API call.
223
+
224
+ ```tsx
225
+ import { DatabaseSchemaType } from "@haustle/notion-orm/build/db/books";
226
+
227
+ async function addPageToNotionDatabase() {
228
+ const example: DatabaseSchemaType = {
229
+ bookName: "How to Change Your Mind",
230
+ genre: ["Non-fiction"],
231
+ };
232
+
233
+ // make sure this route reflects your API path
234
+ await fetch("/api/notion/books", {
235
+ method: "POST",
236
+ body: JSON.stringify(example),
237
+ });
238
+ }
239
+ ```
240
+
241
+ ```jsx
242
+ <button onClick={ async() => await addPageToNotionDatabase()}>
243
+ ```
244
+
245
+ Example API endpoint below, where we’re taking the body of type `DatabaseSchemaType` and passing it into the respected databases `add()` function to add a new page to the database. Learn more about _Next.js_ API’s and routing [here](https://nextjs.org/docs/api-routes/introduction).
246
+
247
+ ```tsx
248
+ // pages/api/notion/yourDatabaseName.ts
249
+
250
+ import type { NextApiRequest, NextApiResponse } from "next";
251
+ import {
252
+ DatabaseSchemaType,
253
+ yourDatabaseName,
254
+ } from "@haustle/notion-orm/build/db/yourDatabaseName";
255
+
256
+ export default async function handler(
257
+ req: NextApiRequest,
258
+ res: NextApiResponse
259
+ ) {
260
+ const { method, body } = req;
261
+
262
+ if (method === "POST") {
263
+ const bodyJSON = JSON.parse(body) as DatabaseSchemaType;
264
+ await yourDatabaseName.add(bodyJSON);
265
+ }
266
+ }
267
+ ```
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Internal constants for AST and db-client modules.
3
+ */
4
+ /** Generated DB files directory — always relative to the consuming project */
5
+ export declare const DATABASES_DIR: string;
6
+ /** File system paths for CLI output */
7
+ export declare const AST_FS_PATHS: {
8
+ /** metadata.json inside generated/ */
9
+ readonly metadataFile: string;
10
+ /** src/index.ts — the dynamic barrel rewritten on every generate */
11
+ readonly sourceIndexTs: string;
12
+ /** generated/index.ts — barrel exporting all DB clients */
13
+ readonly generatedBarrelTs: string;
14
+ };
15
+ export declare const AST_FS_FILENAMES: {
16
+ readonly METADATA: "metadata.json";
17
+ readonly INDEX_TS: "index.ts";
18
+ };
19
+ /** Import path strings used when generating TypeScript code */
20
+ export declare const AST_IMPORT_PATHS: {
21
+ readonly DATABASE_CLIENT: "../src/db-client/DatabaseClient" | "@elumixor/notion-orm";
22
+ readonly QUERY_TYPES: "@elumixor/notion-orm" | "../src/db-client/queryTypes";
23
+ readonly ZOD: "zod";
24
+ readonly databaseClass: (className: string) => string;
25
+ };
26
+ export declare const AST_RUNTIME_CONSTANTS: {
27
+ readonly NOTION_API_VERSION: "2025-09-03";
28
+ readonly PACKAGE_LOG_PREFIX: "[@elumixor/notion-orm]";
29
+ readonly CLI_GENERATE_COMMAND: "notion generate";
30
+ readonly SCHEMA_DRIFT_PREFIX: "Schema drift detected";
31
+ readonly SCHEMA_DRIFT_HELP_MESSAGE: "Run `notion generate` to refresh all database schemas.";
32
+ };
33
+ export declare const AST_TYPE_NAMES: {
34
+ readonly DATABASE_SCHEMA_TYPE: "DatabaseSchemaType";
35
+ readonly COLUMN_NAME_TO_COLUMN_TYPE: "ColumnNameToColumnType";
36
+ readonly QUERY_SCHEMA_TYPE: "QuerySchemaType";
37
+ readonly PROPERTY_VALUES_SUFFIX: "PropertyValues";
38
+ };