-
-
Notifications
You must be signed in to change notification settings - Fork 691
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1677 from drizzle-team/beta
Beta
- Loading branch information
Showing
38 changed files
with
5,486 additions
and
427 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
## Fixes | ||
|
||
- Added improvements to the planescale relational tests #1579 - thanks @Angelelz | ||
- [Pg] FIX: correct string escaping for empty PgArrays #1640 - thanks @Angelelz | ||
- Fix wrong syntax for exists fn in sqlite #1647 - thanks @Angelelz | ||
- Properly handle dates in AWS Data API | ||
- Fix Hermes mixins constructor issue | ||
|
||
## ESLint Drizzle Plugin, v0.2.3 | ||
|
||
``` | ||
npm i eslint-plugin-drizzle@0.2.3 | ||
``` | ||
|
||
🎉 **[ESLint] Add support for functions and improve error messages #1586 - thanks @ngregrichardson** | ||
|
||
- Allowed Drizzle object to be or to be retrieved from a function, e.g. | ||
- Added better context to the suggestion in the error message. | ||
|
||
## New Drivers | ||
|
||
### 🎉 Expo SQLite Driver is available | ||
|
||
For starting with Expo SQLite Driver, you need to install `expo-sqlite` and `drizzle-orm` packages. | ||
|
||
```bash | ||
npm install drizzle-orm expo-sqlite@next | ||
``` | ||
|
||
Then, you can use it like this: | ||
|
||
```ts | ||
import { drizzle } from "drizzle-orm/expo-sqlite"; | ||
import { openDatabaseSync } from "expo-sqlite/next"; | ||
|
||
const expoDb = openDatabaseSync("db.db"); | ||
|
||
const db = drizzle(expoDb); | ||
|
||
await db.select().from(...)... | ||
|
||
// or | ||
|
||
db.select().from(...).then(...); | ||
|
||
// or | ||
|
||
db.select().from(...).all(); | ||
``` | ||
|
||
If you want to use Drizzle Migrations, you need to update babel and metro configuration files. | ||
|
||
1. Install `babel-plugin-inline-import` package. | ||
|
||
```bash | ||
npm install babel-plugin-inline-import | ||
``` | ||
|
||
2. Update `babel.config.js` and `metro.config.js` files. | ||
|
||
babel.config.js | ||
|
||
```diff | ||
module.exports = function(api) { | ||
api.cache(true); | ||
|
||
return { | ||
presets: ['babel-preset-expo'], | ||
+ plugins: [["inline-import", { "extensions": [".sql"] }]] | ||
}; | ||
}; | ||
``` | ||
|
||
metro.config.js | ||
|
||
```diff | ||
const { getDefaultConfig } = require('expo/metro-config'); | ||
|
||
/** @type {import('expo/metro-config').MetroConfig} */ | ||
const config = getDefaultConfig(__dirname); | ||
|
||
+config.resolver.sourceExts.push('sql'); | ||
|
||
module.exports = config; | ||
``` | ||
|
||
3. Create `drizzle.config.ts` file in your project root folder. | ||
|
||
```ts | ||
import type { Config } from 'drizzle-kit'; | ||
|
||
export default { | ||
schema: './db/schema.ts', | ||
out: './drizzle', | ||
driver: 'expo', | ||
} satisfies Config; | ||
``` | ||
|
||
After creating schema file and drizzle.config.ts file, you can generate migrations like this: | ||
|
||
```bash | ||
npx drizzle-kit generate:sqlite | ||
``` | ||
|
||
Then you need to import `migrations.js` file in your `App.tsx` file from `./drizzle` folder and use hook `useMigrations` or `migrate` function. | ||
|
||
```tsx | ||
import { drizzle } from "drizzle-orm/expo-sqlite"; | ||
import { openDatabaseSync } from "expo-sqlite/next"; | ||
import { useMigrations } from 'drizzle-orm/expo-sqlite/migrator'; | ||
import migrations from './drizzle/migrations'; | ||
|
||
const expoDb = openDatabaseSync("db.db"); | ||
|
||
const db = drizzle(expoDb); | ||
|
||
export default function App() { | ||
const { success, error } = useMigrations(db, migrations); | ||
|
||
if (error) { | ||
return ( | ||
<View> | ||
<Text>Migration error: {error.message}</Text> | ||
</View> | ||
); | ||
} | ||
|
||
if (!success) { | ||
return ( | ||
<View> | ||
<Text>Migration is in progress...</Text> | ||
</View> | ||
); | ||
} | ||
|
||
return ...your application component; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# eslint-plugin-drizzle 0.2.3 | ||
|
||
- Added better context to the suggestion in the error message | ||
- fix: Correct detection of `drizzleObjectName` when it's retrieved from or is a function | ||
- chore: Refactored duplicate code in `utils/options.ts` into `isDrizzleObjName` function |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import type { SQLiteDatabase, SQLiteRunResult } from 'expo-sqlite/next'; | ||
import { DefaultLogger } from '~/logger.ts'; | ||
import { | ||
createTableRelationsHelpers, | ||
extractTablesRelationalConfig, | ||
type RelationalSchemaConfig, | ||
type TablesRelationalConfig, | ||
} from '~/relations.ts'; | ||
import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; | ||
import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; | ||
import type { DrizzleConfig } from '~/utils.ts'; | ||
import { ExpoSQLiteSession } from './session.ts'; | ||
|
||
export type ExpoSQLiteDatabase< | ||
TSchema extends Record<string, unknown> = Record<string, never>, | ||
> = BaseSQLiteDatabase<'sync', SQLiteRunResult, TSchema>; | ||
|
||
export function drizzle<TSchema extends Record<string, unknown> = Record<string, never>>( | ||
client: SQLiteDatabase, | ||
config: DrizzleConfig<TSchema> = {}, | ||
): ExpoSQLiteDatabase<TSchema> { | ||
const dialect = new SQLiteSyncDialect(); | ||
let logger; | ||
if (config.logger === true) { | ||
logger = new DefaultLogger(); | ||
} else if (config.logger !== false) { | ||
logger = config.logger; | ||
} | ||
|
||
let schema: RelationalSchemaConfig<TablesRelationalConfig> | undefined; | ||
if (config.schema) { | ||
const tablesConfig = extractTablesRelationalConfig( | ||
config.schema, | ||
createTableRelationsHelpers, | ||
); | ||
schema = { | ||
fullSchema: config.schema, | ||
schema: tablesConfig.tables, | ||
tableNamesMap: tablesConfig.tableNamesMap, | ||
}; | ||
} | ||
|
||
const session = new ExpoSQLiteSession(client, dialect, schema, { logger }); | ||
return new BaseSQLiteDatabase('sync', dialect, session, schema) as ExpoSQLiteDatabase<TSchema>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './driver.ts'; | ||
export * from './session.ts'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import { useEffect, useReducer } from "react"; | ||
import type { MigrationMeta } from '~/migrator.ts'; | ||
import type { ExpoSQLiteDatabase } from './driver.ts'; | ||
|
||
interface MigrationConfig { | ||
journal: { | ||
entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; | ||
}; | ||
migrations: Record<string, string>; | ||
} | ||
|
||
async function readMigrationFiles({ journal, migrations }: MigrationConfig): Promise<MigrationMeta[]> { | ||
const migrationQueries: MigrationMeta[] = []; | ||
|
||
for await (const journalEntry of journal.entries) { | ||
const query = migrations[`m${journalEntry.idx.toString().padStart(4, '0')}`]; | ||
|
||
if (!query) { | ||
throw new Error(`Missing migration: ${journalEntry.tag}`); | ||
} | ||
|
||
try { | ||
const result = query.split('--> statement-breakpoint').map((it) => { | ||
return it; | ||
}); | ||
|
||
migrationQueries.push({ | ||
sql: result, | ||
bps: journalEntry.breakpoints, | ||
folderMillis: journalEntry.when, | ||
hash: '', | ||
}); | ||
} catch { | ||
throw new Error(`Failed to parse migration: ${journalEntry.tag}`); | ||
} | ||
} | ||
|
||
return migrationQueries; | ||
} | ||
|
||
export async function migrate<TSchema extends Record<string, unknown>>( | ||
db: ExpoSQLiteDatabase<TSchema>, | ||
config: MigrationConfig, | ||
) { | ||
const migrations = await readMigrationFiles(config); | ||
return db.dialect.migrate(migrations, db.session); | ||
} | ||
|
||
interface State { | ||
success: boolean; | ||
error?: Error; | ||
} | ||
|
||
type Action = | ||
| { type: 'migrating' } | ||
| { type: 'migrated'; payload: true } | ||
| { type: 'error'; payload: Error } | ||
|
||
export const useMigrations = (db: ExpoSQLiteDatabase<any>, migrations: { | ||
journal: { | ||
entries: { idx: number; when: number; tag: string; breakpoints: boolean }[]; | ||
}; | ||
migrations: Record<string, string>; | ||
}): State => { | ||
const initialState: State = { | ||
success: false, | ||
error: undefined, | ||
} | ||
|
||
const fetchReducer = (state: State, action: Action): State => { | ||
switch (action.type) { | ||
case 'migrating': { | ||
return { ...initialState } | ||
} | ||
case 'migrated': { | ||
return { ...initialState, success: action.payload } | ||
} | ||
case 'error': { | ||
return { ...initialState, error: action.payload } | ||
} | ||
default: { | ||
return state | ||
} | ||
} | ||
} | ||
|
||
const [state, dispatch] = useReducer(fetchReducer, initialState); | ||
|
||
useEffect(() => { | ||
dispatch({ type: 'migrating' }) | ||
try { | ||
migrate(db, migrations as any).then(() => { | ||
dispatch({ type: 'migrated', payload: true }) | ||
}) | ||
} catch (error) { | ||
dispatch({ type: 'error', payload: error as Error }) | ||
} | ||
}, []); | ||
|
||
return state; | ||
} |
Oops, something went wrong.